comparison dbutil.c @ 62:20563735e8b5

just checkpointing
author Matt Johnston <matt@ucc.asn.au>
date Tue, 10 Aug 2004 17:09:52 +0000
parents 095d689fed16
children dcc43965928f
comparison
equal deleted inserted replaced
61:3a4f0ef1e8c3 62:20563735e8b5
111 fprintf(stderr, "\n"); 111 fprintf(stderr, "\n");
112 va_end(param); 112 va_end(param);
113 } 113 }
114 #endif /* DEBUG_TRACE */ 114 #endif /* DEBUG_TRACE */
115 115
116 /* Listen on address:port. Unless address is NULL, in which case listen on
117 * everything (ie 0.0.0.0, or ::1 - note that this is IPv? agnostic. Linux is
118 * broken with respect to listening to v6 or v4, so the addresses you get when
119 * people connect will be wrong. It doesn't break things, just looks quite
120 * ugly. Returns the number of sockets bound on success, or -1 on failure. On
121 * failure, if errstring wasn't NULL, it'll be a newly malloced error
122 * string.*/
123 int dropbear_listen(const char* address, const char* port,
124 int *socks, unsigned int sockcount, char **errstring, int *maxfd) {
125
126 struct addrinfo hints, *res, *res0;
127 int err;
128 unsigned int nsock;
129 struct linger linger;
130 int val;
131 int sock;
132
133 TRACE(("enter dropbear_listen"));
134
135 memset(&hints, 0, sizeof(hints));
136 hints.ai_family = AF_UNSPEC; /* TODO: let them flag v4 only etc */
137 hints.ai_socktype = SOCK_STREAM;
138 hints.ai_flags = AI_PASSIVE;
139 err = getaddrinfo(address, port, &hints, &res0);
140
141 if (err) {
142 if (errstring != NULL && *errstring == NULL) {
143 int len;
144 len = 20 + strlen(gai_strerror(err));
145 *errstring = (char*)m_malloc(len);
146 snprintf(*errstring, len, "Error resolving: %s", gai_strerror(err));
147 }
148 TRACE(("leave dropbear_listen: failed resolving"));
149 return -1;
150 }
151
152
153 nsock = 0;
154 for (res = res0; res != NULL && nsock < sockcount;
155 res = res->ai_next) {
156
157 /* Get a socket */
158 socks[nsock] = socket(res->ai_family, res->ai_socktype,
159 res->ai_protocol);
160
161 sock = socks[nsock]; /* For clarity */
162
163 if (sock < 0) {
164 err = errno;
165 TRACE(("socket() failed"));
166 continue;
167 }
168
169 /* Various useful socket options */
170 val = 1;
171 /* set to reuse, quick timeout */
172 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &val, sizeof(val));
173 linger.l_onoff = 1;
174 linger.l_linger = 5;
175 setsockopt(sock, SOL_SOCKET, SO_LINGER, (void*)&linger, sizeof(linger));
176
177 /* disable nagle */
178 setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&val, sizeof(val));
179
180 if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) {
181 err = errno;
182 close(sock);
183 TRACE(("bind() failed"));
184 continue;
185 }
186
187 if (listen(sock, 20) < 0) {
188 err = errno;
189 close(sock);
190 TRACE(("listen() failed"));
191 continue;
192 }
193
194 *maxfd = MAX(*maxfd, sock);
195
196 nsock++;
197 }
198
199 if (nsock == 0) {
200 if (errstring != NULL && *errstring == NULL) {
201 int len;
202 len = 20 + strlen(strerror(err));
203 *errstring = (char*)m_malloc(len);
204 snprintf(*errstring, len, "Error connecting: %s", strerror(err));
205 TRACE(("leave dropbear_listen: failure, %s", strerror(err)));
206 return -1;
207 }
208 }
209
210 TRACE(("leave dropbear_listen: success, %d socks bound", nsock));
211 return nsock;
212 }
213
116 /* Connect via TCP to a host. Connection will try ipv4 or ipv6, will 214 /* Connect via TCP to a host. Connection will try ipv4 or ipv6, will
117 * return immediately if nonblocking is set */ 215 * return immediately if nonblocking is set. On failure, if errstring
216 * wasn't null, it will be a newly malloced error message */
217
218 /* TODO: maxfd */
118 int connect_remote(const char* remotehost, const char* remoteport, 219 int connect_remote(const char* remotehost, const char* remoteport,
119 int nonblocking, char ** errstring) { 220 int nonblocking, char ** errstring) {
120 221
121 struct addrinfo *res0 = NULL, *res = NULL, hints; 222 struct addrinfo *res0 = NULL, *res = NULL, hints;
122 int sock; 223 int sock;
195 /* (err is used as a dummy var here) */ 296 /* (err is used as a dummy var here) */
196 setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&err, sizeof(err)); 297 setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&err, sizeof(err));
197 } 298 }
198 299
199 freeaddrinfo(res0); 300 freeaddrinfo(res0);
200 301 if (sock > 0 && errstring != NULL && *errstring != NULL) {
201 TRACE(("leave connect_remote: sock %d", sock)); 302 m_free(*errstring);
303 }
304
305 TRACE(("leave connect_remote: sock %d\n", sock));
202 return sock; 306 return sock;
203 } 307 }
204 308
205 /* Return a string representation of the socket address passed. The return 309 /* Return a string representation of the socket address passed. The return
206 * value is allocated with malloc() */ 310 * value is allocated with malloc() */
207 unsigned char * getaddrstring(struct sockaddr * addr) { 311 unsigned char * getaddrstring(struct sockaddr_storage* addr, int withport) {
208 312
209 char *retstring; 313 char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
210 314 char *retstring = NULL;
211 /* space for "255.255.255.255:65535\0" = 22 */ 315 int ret;
212 retstring = m_malloc(22); 316 unsigned int len;
213 317
214 switch (addr->sa_family) { 318 len = sizeof(struct sockaddr_storage);
215 case PF_INET: 319
216 snprintf(retstring, 22, "%s:%hu", 320 ret = getnameinfo((struct sockaddr*)addr, len, hbuf, sizeof(hbuf),
217 inet_ntoa(((struct sockaddr_in *)addr)->sin_addr), 321 sbuf, sizeof(sbuf), NI_NUMERICSERV | NI_NUMERICHOST);
218 ((struct sockaddr_in *)addr)->sin_port); 322
219 break; 323 if (ret != 0) {
220 324 /* This is a fairly bad failure - it'll fallback to IP if it
221 default: 325 * just can't resolve */
222 /* XXX ipv6 */ 326 dropbear_exit("failed lookup (%d, %d)", ret, errno);
223 strcpy(retstring, "Bad protocol"); 327 }
224 328
225 } 329 if (withport) {
330 len = strlen(hbuf) + 2 + strlen(sbuf);
331 retstring = (char*)m_malloc(len);
332 snprintf(retstring, len, "%s:%s", hbuf, sbuf);
333 } else {
334 retstring = m_strdup(hbuf);
335 }
336
226 return retstring; 337 return retstring;
227 338
228 } 339 }
229 340
230 /* Get the hostname corresponding to the address addr. On failure, the IP 341 /* Get the hostname corresponding to the address addr. On failure, the IP
231 * address is returned. The return value is allocated with strdup() */ 342 * address is returned. The return value is allocated with strdup() */
232 char* getaddrhostname(struct sockaddr * addr) { 343 char* getaddrhostname(struct sockaddr_storage * addr) {
233 344
234 struct hostent *host = NULL; 345 char hbuf[NI_MAXHOST];
235 char * retstring; 346 char sbuf[NI_MAXSERV];
236 347 int ret;
237 #ifdef DO_HOST_LOOKUP 348 unsigned int len;
238 host = gethostbyaddr((char*)&((struct sockaddr_in*)addr)->sin_addr, 349
239 sizeof(struct in_addr), AF_INET); 350 len = sizeof(struct sockaddr_storage);
240 #endif 351
241 352 ret = getnameinfo((struct sockaddr*)addr, len, hbuf, sizeof(hbuf),
242 if (host == NULL) { 353 sbuf, sizeof(sbuf), NI_NUMERICSERV);
243 /* return the address */ 354
244 retstring = inet_ntoa(((struct sockaddr_in *)addr)->sin_addr); 355 if (ret != 0) {
245 } else { 356 /* On some systems (Darwin does it) we get EINTR from getnameinfo
246 /* return the hostname */ 357 * somehow. Eew. So we'll just return the IP, since that doesn't seem
247 retstring = host->h_name; 358 * to exhibit that behaviour. */
248 } 359 return getaddrstring(addr, 0);
249 360 }
250 return m_strdup(retstring); 361
251 } 362 return m_strdup(hbuf);
363 }
364
252 #ifdef DEBUG_TRACE 365 #ifdef DEBUG_TRACE
253 void printhex(unsigned char* buf, int len) { 366 void printhex(unsigned char* buf, int len) {
254 367
255 int i; 368 int i;
256 369