Mercurial > dropbear
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 |