1 /*
2  * Copyright (c) 2014, 2015, 2016  Machine Zone, Inc.
3  *
4  * Original author: Lev Walkin <lwalkin@machinezone.com>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14 
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 #define _GNU_SOURCE
28 #include <getopt.h>
29 #include <sysexits.h>
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <unistd.h>
33 #include <string.h>
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <ifaddrs.h>
37 #include <net/if.h>
38 #include <netinet/in.h>
39 #include <arpa/inet.h>
40 #include <netdb.h> /* gethostbyname(3) */
41 #include <fcntl.h>
42 #include <errno.h>
43 #include <assert.h>
44 
45 #include "tcpkali_common.h"
46 #include "tcpkali_logging.h"
47 #include "tcpkali_iface.h"
48 
49 /*
50  * Note: struct sockaddr_in6 is larger than struct sockaddr, hence
51  * the storage should be bigger. However, we shall not dereference
52  * the AF_INET (struct sockaddr_in *) as it were a larger structure.
53  * Therefore this code is rather complex.
54  */
55 void
address_add(struct addresses * aseq,struct sockaddr * sa)56 address_add(struct addresses *aseq, struct sockaddr *sa) {
57     /* Reallocate a bigger list and continue. Don't laugh. */
58     aseq->addrs =
59         realloc(aseq->addrs, (aseq->n_addrs + 1) * sizeof(aseq->addrs[0]));
60     assert(aseq->addrs);
61     switch(sa->sa_family) {
62     case AF_INET:
63         *(struct sockaddr_in *)&aseq->addrs[aseq->n_addrs] =
64             *(struct sockaddr_in *)sa;
65         aseq->n_addrs++;
66         break;
67     case AF_INET6:
68         *(struct sockaddr_in6 *)&aseq->addrs[aseq->n_addrs] =
69             *(struct sockaddr_in6 *)sa;
70         aseq->n_addrs++;
71         break;
72     default:
73         assert(!"Not IPv4 and not IPv6");
74         break;
75     }
76 }
77 
78 typedef enum {
79     SMATCH_ADDR_ONLY,
80     SMATCH_ADDR_PORT,
81 } sockaddrs_cmp_e;
82 static int
sockaddrs_match(struct sockaddr * sa,struct sockaddr * sb,sockaddrs_cmp_e cmp)83 sockaddrs_match(struct sockaddr *sa, struct sockaddr *sb, sockaddrs_cmp_e cmp) {
84     if(sa->sa_family == sb->sa_family) {
85         switch(sa->sa_family) {
86         case AF_INET: {
87             struct sockaddr_in *sia = (struct sockaddr_in *)sa;
88             struct sockaddr_in *sib = (struct sockaddr_in *)sb;
89             if((cmp != SMATCH_ADDR_PORT || sia->sin_port == sib->sin_port)
90                && sia->sin_addr.s_addr == sib->sin_addr.s_addr) {
91                 return 1;
92             }
93         } break;
94         case AF_INET6: {
95             struct sockaddr_in6 *sia = (struct sockaddr_in6 *)sa;
96             struct sockaddr_in6 *sib = (struct sockaddr_in6 *)sb;
97             if((cmp != SMATCH_ADDR_PORT || sia->sin6_port == sib->sin6_port)
98                && 0 == memcmp(&sia->sin6_addr, &sib->sin6_addr,
99                               sizeof(struct in6_addr))) {
100                 return 1;
101             }
102         } break;
103         }
104     }
105     return 0;
106 }
107 
108 /*
109  * Return non-zero if such address already exists.
110  */
111 static int
address_is_member(struct addresses * aseq,struct sockaddr * sb)112 address_is_member(struct addresses *aseq, struct sockaddr *sb) {
113     for(size_t i = 0; i < aseq->n_addrs; i++) {
114         struct sockaddr *sa = (struct sockaddr *)&aseq->addrs[i];
115         if(sockaddrs_match(sa, sb, SMATCH_ADDR_PORT)) return 1;
116     }
117 
118     return 0;
119 }
120 
121 /*
122  * Display destination addresses with a given prefix, separator and suffix.
123  */
124 void
fprint_addresses(FILE * fp,char * prefix,char * separator,char * suffix,struct addresses addresses)125 fprint_addresses(FILE *fp, char *prefix, char *separator, char *suffix,
126                  struct addresses addresses) {
127     for(size_t n = 0; n < addresses.n_addrs; n++) {
128         if(n == 0) {
129             fprintf(fp, "%s", prefix);
130         } else {
131             fprintf(fp, "%s", separator);
132         }
133         char buf[INET6_ADDRSTRLEN + 64];
134         fprintf(stderr, "%s",
135                 format_sockaddr(&addresses.addrs[n], buf, sizeof(buf)));
136         if(n == addresses.n_addrs - 1) {
137             fprintf(fp, "%s", suffix);
138         }
139     }
140 }
141 
142 /*
143  * Printable representation of a sockaddr.
144  */
145 const char *
format_sockaddr(struct sockaddr_storage * ss,char * buf,size_t size)146 format_sockaddr(struct sockaddr_storage *ss, char *buf, size_t size) {
147     void *in_addr;
148     uint16_t nport;
149     switch(ss->ss_family) {
150     case AF_INET:
151         in_addr = &((struct sockaddr_in *)ss)->sin_addr;
152         nport = ((struct sockaddr_in *)ss)->sin_port;
153         break;
154     case AF_INET6:
155         in_addr = &((struct sockaddr_in6 *)ss)->sin6_addr;
156         nport = ((struct sockaddr_in6 *)ss)->sin6_port;
157         break;
158     default:
159         assert(!"ipv4 or ipv6 expected");
160         return "<unknown>";
161     }
162     char ipbuf[INET6_ADDRSTRLEN];
163     const char *ip = inet_ntop(ss->ss_family, in_addr, ipbuf, sizeof(ipbuf));
164     snprintf(buf, size, "[%s]:%d", ip, ntohs(nport));
165     return buf;
166 }
167 
168 /*
169  * Given a port, detect which addresses we can listen on, using this port.
170  */
171 struct addresses
detect_listen_addresses(const char * local_hostname,int listen_port)172 detect_listen_addresses(const char *local_hostname, int listen_port) {
173     struct addresses addresses = {0, 0};
174     struct addrinfo hints = {
175         .ai_family = AF_UNSPEC,
176         .ai_socktype = SOCK_STREAM,
177         .ai_protocol = IPPROTO_TCP,
178         .ai_flags = AI_PASSIVE | AI_NUMERICSERV | AI_ADDRCONFIG};
179     char service[32];
180     snprintf(service, sizeof(service), "%d", listen_port);
181 
182     struct addrinfo *res;
183     int err = getaddrinfo(local_hostname, service, &hints, &res);
184     if(err != 0) {
185         fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(err));
186         exit(EXIT_FAILURE);
187     }
188 
189     /* Move all of the addresses into the separate storage */
190     for(struct addrinfo *tmp = res; tmp; tmp = tmp->ai_next) {
191         address_add(&addresses, tmp->ai_addr);
192     }
193 
194     freeaddrinfo(res);
195 
196     fprint_addresses(stderr, "Listen on: ", "\nListen on: ", "\n", addresses);
197 
198     return addresses;
199 }
200 
201 /*
202  * Check whether we can bind to a specified IP.
203  */
204 static int
check_if_bindable_ip(struct sockaddr_storage * ss)205 check_if_bindable_ip(struct sockaddr_storage *ss) {
206     int rc;
207     int lsock = socket(ss->ss_family, SOCK_STREAM, IPPROTO_TCP);
208     assert(lsock != -1);
209     rc = bind(lsock, (struct sockaddr *)ss, sockaddr_len(ss));
210     close(lsock);
211     if(rc == -1) {
212         char buf[256];
213         fprintf(stderr, "%s is not local: %s\n",
214                 format_sockaddr(ss, buf, sizeof(buf)), strerror(errno));
215         return -1;
216     }
217     return 0;
218 }
219 
220 /*
221  * Parse the specified IP as it were a source IP, and add it to the list.
222  */
223 int
add_source_ip(struct addresses * addresses,const char * optarg)224 add_source_ip(struct addresses *addresses, const char *optarg) {
225     struct addrinfo hints = {.ai_family = AF_UNSPEC,
226                              .ai_socktype = SOCK_STREAM,
227                              .ai_protocol = IPPROTO_TCP,
228                              .ai_flags = AI_PASSIVE | AI_ADDRCONFIG};
229 
230     struct addrinfo *res;
231     int err = getaddrinfo(optarg, NULL, &hints, &res);
232     if(err != 0) {
233         fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(err));
234         return -1;
235     }
236 
237     /* Move all of the addresses into the separate storage */
238     for(struct addrinfo *tmp = res; tmp; tmp = tmp->ai_next) {
239         address_add(addresses, tmp->ai_addr);
240         if(check_if_bindable_ip(&addresses->addrs[addresses->n_addrs - 1])
241            < 0) {
242             freeaddrinfo(res);
243             return -1;
244         }
245     }
246 
247     freeaddrinfo(res);
248 
249     return 0;
250 }
251 
252 static void
reset_port(struct sockaddr_storage * ss,in_port_t new_port_value)253 reset_port(struct sockaddr_storage *ss, in_port_t new_port_value) {
254     switch(ss->ss_family) {
255     case AF_INET: {
256         struct sockaddr_in *sin = (struct sockaddr_in *)ss;
257         sin->sin_port = new_port_value;
258     } break;
259     case AF_INET6: {
260         struct sockaddr_in6 *sin = (struct sockaddr_in6 *)ss;
261         sin->sin6_port = new_port_value;
262     } break;
263     default:
264         assert(!"Not IPv4 and not IPv6");
265         break;
266     }
267 }
268 
269 /*
270  * Return the name of the interface which contains given IP.
271  */
272 static const char *
interface_by_addr(struct ifaddrs * ifp,struct sockaddr * addr)273 interface_by_addr(struct ifaddrs *ifp, struct sockaddr *addr) {
274     for(; ifp; ifp = ifp->ifa_next) {
275         if(ifp->ifa_addr
276            && sockaddrs_match(addr, ifp->ifa_addr, SMATCH_ADDR_ONLY)) {
277             return ifp->ifa_name;
278         }
279     }
280 
281     return NULL;
282 }
283 
284 static int
detect_local_ip_for_remote(struct ifaddrs * ifp,struct sockaddr_storage * ss,struct sockaddr_storage * r_local_addr)285 detect_local_ip_for_remote(struct ifaddrs *ifp, struct sockaddr_storage *ss,
286                            struct sockaddr_storage *r_local_addr) {
287     char tmpbuf[128];
288 
289     int sockfd = socket(ss->ss_family, SOCK_STREAM, IPPROTO_TCP);
290     if(sockfd == -1) {
291         fprintf(stderr, "Could not open %s socket: %s\n",
292                 ss->ss_family == AF_INET6 ? "IPv6" : "IPv4", strerror(errno));
293         return -1;
294     }
295 
296     /* Enable non-blocking mode. */
297     int rc = fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL) | O_NONBLOCK);
298     assert(rc != 1);
299 
300     /*
301      * Try connecting to a destination, and figure out the IP of the local
302      * end of the connection while connection is pending. Then close quickly.
303      */
304     rc = connect(sockfd, (struct sockaddr *)ss, sockaddr_len(ss));
305     if(rc == -1 && errno != EINPROGRESS) {
306         fprintf(stderr, "Could not pre-check connection to %s: %s\n",
307                 format_sockaddr(ss, tmpbuf, sizeof(tmpbuf)), strerror(errno));
308         close(sockfd);
309         return -1;
310     } else {
311         /*
312          * We could not connect to an address. Supposedly this is related
313          * to the fact that the system rather early figured we're not
314          * supposed to connect there. It can be related to IP filtering,
315          * or socket resource exhaustion, or the fact that we're connecting
316          * to something very local. A non-blocking connection
317          * to a local host may also result in EINPROGRESS, but that's
318          * probably not guaranteed. So, we check using a different algorithm
319          * if destination IP is local, then just use that interface.
320          */
321         const char *iface = interface_by_addr(ifp, (struct sockaddr *)ss);
322         if(iface) {
323             *r_local_addr = *ss;
324             reset_port(r_local_addr, 0);
325             close(sockfd);
326             return 0;
327         }
328     }
329 
330     socklen_t local_addrlen = sizeof(*r_local_addr);
331     if(getsockname(sockfd, (struct sockaddr *)r_local_addr, &local_addrlen)
332        == -1) {
333         fprintf(stderr,
334                 "Could not get local address when connecting to %s: %s\n",
335                 format_sockaddr(ss, tmpbuf, sizeof(tmpbuf)), strerror(errno));
336         close(sockfd);
337         return -1;
338     } else {
339         /* We're going to bind to that port at some point. Must be zero. */
340         reset_port(r_local_addr, 0);
341     }
342 
343     close(sockfd);
344     return 0;
345 }
346 
347 static int
compare_ifnames(const char * a,const char * b)348 compare_ifnames(const char *a, const char *b) {
349     for(;; a++, b++) {
350         switch(*a) {
351         case '\0':
352         case ':':
353             if(*b == '\0' || *b == ':') break;
354             return -1;
355         default:
356             if(*a == *b) continue;
357             return -1;
358         }
359         break;
360     }
361 
362     return 0;
363 }
364 
365 #ifdef TCPKALI_IFACE_UNIT_TEST
366 int
main()367 main() {
368     const char *non_equivalents[][5] = {{"", "a", "b", "ab", "a0"},
369                                         {"a", "a0", "a1", "b0", "b1"}};
370     const char *equivalents[][5] = {
371         {"", ":", ":0", ":1", ":123"},
372         {"a", "a:", "a:0", "a:1", "a:123"},
373         {"ab", "ab:", "ab:0", "ab:1", "ab:123"},
374         {"bond0", "bond0:", "bond0:0", "bond0:1", "bond0:123"}};
375 
376     /* Test non-equivalence */
377     for(size_t test = 0; test < 2; test++) {
378         for(size_t i = 0; i < 5; i++) {
379             for(size_t j = 0; j < 5; j++) {
380                 if(i == j) continue;
381                 const char *a = non_equivalents[test][i];
382                 const char *b = non_equivalents[test][j];
383                 assert(compare_ifnames(a, b) == -1);
384             }
385         }
386     }
387 
388     /* Test equivalence */
389     for(size_t test = 0; test < 4; test++) {
390         for(size_t i = 0; i < 5; i++) {
391             for(size_t j = 0; j < 5; j++) {
392                 if(i == j) continue;
393                 const char *a = equivalents[test][i];
394                 const char *b = equivalents[test][j];
395                 assert(compare_ifnames(a, b) == 0);
396             }
397         }
398     }
399 
400     return 0;
401 }
402 #endif
403 
404 
405 static int
collect_interface_addresses(struct ifaddrs * ifp,const char * ifname,sa_family_t family,struct addresses * ss)406 collect_interface_addresses(struct ifaddrs *ifp, const char *ifname,
407                             sa_family_t family, struct addresses *ss) {
408     char tmpbuf[256];
409     int found = 0;
410 
411     for(; ifp; ifp = ifp->ifa_next) {
412         if(ifp->ifa_addr && family == ifp->ifa_addr->sa_family
413            && compare_ifnames(ifp->ifa_name, ifname) == 0) {
414             /* Add address if it is not already there. */
415             if(!address_is_member(ss, ifp->ifa_addr)) {
416                 fprintf(
417                     stderr, "Interface %s address %s\n", ifname,
418                     format_sockaddr((struct sockaddr_storage *)ifp->ifa_addr,
419                                     tmpbuf, sizeof(tmpbuf)));
420                 address_add(ss, ifp->ifa_addr);
421             }
422             found = 1;
423         }
424     }
425 
426     return found ? 0 : -1;
427 }
428 
429 /*
430  * Given a list of destination addresses, populate the list of source
431  * addresses with compatible source (local) IPs.
432  */
433 int
detect_source_ips(struct addresses * dsts,struct addresses * srcs)434 detect_source_ips(struct addresses *dsts, struct addresses *srcs) {
435     struct ifaddrs *interfaces = 0;
436 
437     int rc = getifaddrs(&interfaces);
438     if(rc == -1) {
439         /* Can't get interfaces... Won't try to use several source IPs. */
440         warning(
441             "Can't enumerate interfaces, "
442             "won't use multiple source IPs: %s\n",
443             strerror(errno));
444         return 0;
445     }
446 
447     /* If we are not supposed to go anywhere, we won't invoke this function. */
448     if(dsts->n_addrs == 0) {
449         fprintf(stderr,
450                 "Source IP detection failed: "
451                 "No destination IPs are given\n");
452         freeifaddrs(interfaces);
453         return -1;
454     }
455 
456     sa_family_t common_ss_family = 0;
457 
458     for(size_t dst_idx = 0; dst_idx < dsts->n_addrs; dst_idx++) {
459         struct sockaddr_storage *ds = &dsts->addrs[dst_idx];
460         char tmpbuf[256];
461 
462         /*
463          * For now, we can reliably detect source ips only
464          * when the address families of the destination ips are the same.
465          */
466         if(common_ss_family == 0) {
467             common_ss_family = ds->ss_family;
468         } else if(common_ss_family != ds->ss_family) {
469             warning(
470                 "Could not detect local address when connecting to %s:"
471                 " Multiple incompatible address families in destination.\n",
472                 format_sockaddr(ds, tmpbuf, sizeof(tmpbuf)));
473             warning("Would not open more than 64k connections to %s\n",
474                     format_sockaddr(ds, tmpbuf, sizeof(tmpbuf)));
475             srcs->n_addrs = 0;
476             freeifaddrs(interfaces);
477             return 0;
478         }
479 
480         /*
481          * Attempt to create a connection and see what our
482          * local address looks like. Then search for that address
483          * among the interfaces.
484          */
485         struct sockaddr_storage local_addr;
486         if(detect_local_ip_for_remote(interfaces, ds, &local_addr)) {
487             freeifaddrs(interfaces);
488             return -1;
489         }
490 
491         const char *ifname =
492             interface_by_addr(interfaces, (struct sockaddr *)&local_addr);
493         if(ifname == NULL) {
494             warning("Can't determine local interface to connect to %s\n",
495                     format_sockaddr(ds, tmpbuf, sizeof(tmpbuf)));
496             warning("Would not open more than 64k connections to %s\n",
497                     format_sockaddr(ds, tmpbuf, sizeof(tmpbuf)));
498             srcs->n_addrs = 0;
499             freeifaddrs(interfaces);
500             return 0;
501         }
502 
503         if(collect_interface_addresses(interfaces, ifname, ds->ss_family, srcs)
504            == 0) {
505             fprintf(stderr, "Using interface %s to connect to %s\n", ifname,
506                     format_sockaddr(ds, tmpbuf, sizeof(tmpbuf)));
507         } else {
508             fprintf(stderr, "Failed to collect IPs from interface %s\n",
509                     ifname);
510             freeifaddrs(interfaces);
511             return -1;
512         }
513     }
514 
515     freeifaddrs(interfaces);
516     return 0;
517 }
518