/* getifname.c -- network interface handling * Copyright(C) 1999,2000,2001 Salvatore Sanfilippo * Copyright(C) 2001 by Nicolas Jombart * This code is under the GPL license */ /* BSD support thanks to Nicolas Jombart */ #include /* perror */ #include #include #include #include #include #include /* struct sockaddr_in */ #include /* inet_ntoa */ #include #include /* close */ #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || \ defined(__bsdi__) || defined(__APPLE__) #include #include #include #endif /* defined(__*BSD__) */ #include "hping2.h" #include "globals.h" #if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && \ !defined(__linux__) && !defined(__sun__) && !defined(__bsdi__) && \ !defined(__APPLE__) #error Sorry, interface code not implemented. #endif #ifdef __sun__ #include #include #include #endif static int get_output_if(struct SOCKADDR *dest, struct SOCKADDR *ifip); #if (defined OSTYPE_LINUX) || (defined __sun__) char * get_v6_if_name(__u8 *ip) { FILE *fd; char buf[1024]; char addr[33]; int i; for(i = 0; i < 16; i++) sprintf(addr + i * 2, "%02x", ip[i]); if(!(fd = fopen("/proc/net/if_inet6", "r"))) { perror("Warning: Unable to open /proc/net/if_inet6\n"); return NULL; } while(fgets(buf, sizeof(buf), fd)) { if(!strncmp(buf, addr, 32)) { sscanf(buf, "%*32s %*02x %*02x %*02x %*02x %40s\n", ifname); return ifname; } } fclose(fd); return NULL; } int get_if_name(void) { int fd; struct ifconf ifc; struct ifreq ibuf[16], ifr, *ifrp, *ifend; struct SOCKADDR sa; struct SOCKADDR output_if_addr; int known_output_if = 0; /* Try to get the output interface address according to * the OS routing table */ if (ifname[0] == '\0') { if (get_output_if(&remote, &output_if_addr) == 0) { known_output_if = 1; inet_ntop(opt_af, ADDR(&output_if_addr), ifstraddr, sizeof(ifstraddr)); if(opt_ipv6) get_v6_if_name((__u8 *)&((struct sockaddr_in6*)&output_if_addr)->sin6_addr.s6_addr); memcpy(&local, &output_if_addr, sizeof(local)); if (opt_debug) printf("DEBUG: Output interface address: %s\n", ifstraddr); } else { fprintf(stderr, "Warning: Unable to guess the output " "interface\n"); } } if ( (fd = socket(opt_af, SOCK_DGRAM, 0)) == -1) { perror("[get_if_name] socket(AF_INET, SOCK_DGRAM, 0)"); return -1; } memset(ibuf, 0, sizeof(struct ifreq)*16); ifc.ifc_len = sizeof ibuf; ifc.ifc_buf = (caddr_t) ibuf; ifrp = ibuf; if(ifname[0] == 0) { /* gets interfaces list */ if ( ioctl(fd, SIOCGIFCONF, (char*)&ifc) == -1 || ifc.ifc_len < sizeof(struct ifreq) ) { perror("[get_if_name] ioctl(SIOCGIFCONF)"); close(fd); return -1; } /* ifrp points to buffer and ifend points to buffer's end */ ifend = (struct ifreq*) ((char*)ibuf + ifc.ifc_len); } else ifend = ifrp + 1; for (; ifrp < ifend; ifrp++) { if(ifname[0] == 0) strlcpy(ifr.ifr_name, ifrp->ifr_name, sizeof(ifr.ifr_name)); else strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); if ( ioctl(fd, SIOCGIFFLAGS, (char*)&ifr) == -1) { if (opt_debug) perror("DEBUG: [get_if_name] ioctl(SIOCGIFFLAGS)"); continue; } if (opt_debug) printf("DEBUG: if %s: ", ifr.ifr_name); /* Down interface? */ if ( !(ifr.ifr_flags & IFF_UP) ) { if (opt_debug) printf("DOWN\n"); continue; } if(!opt_ipv6) { if (known_output_if) { /* Get the interface address */ if (ioctl(fd, SIOCGIFADDR, (char*)&ifr) == -1) { perror("[get_if_name] ioctl(SIOCGIFADDR)"); continue; } /* Copy it */ memcpy(&sa, &ifr.ifr_addr, sizeof(struct sockaddr_in)); /* Check if it is what we are looking for */ if ((*(struct sockaddr_in*)&sa).sin_addr.s_addr != (*(struct sockaddr_in*)&output_if_addr).sin_addr.s_addr) { if (opt_debug) printf("The address doesn't match\n"); continue; } } else if (ifname[0] != '\0' && !strstr(ifr.ifr_name, ifname)) { if (opt_debug) printf("Don't Match (but seems to be UP)\n"); continue; } } if (opt_debug) printf("OK\n"); /* interface found, save if name */ strlcpy(ifname, ifr.ifr_name, 1024); /* get if address */ if(!known_output_if) { if ( ioctl(fd, SIOCGIFADDR, (char*)&ifr) == -1) { perror("DEBUG: [get_if_name] ioctl(SIOCGIFADDR)"); exit(1); } /* save if address */ memcpy(&sa, &ifr.ifr_addr, sizeof(struct sockaddr_in)); inet_ntop(opt_af, ADDR(&output_if_addr), ifstraddr, sizeof(ifstraddr)); } /* get if mtu */ if ( ioctl(fd, SIOCGIFMTU, (char*)&ifr) == -1) { perror("Warning: [get_if_name] ioctl(SIOCGIFMTU)"); fprintf(stderr, "Using a fixed MTU of 1500\n"); h_if_mtu = 1500; } else { #ifdef __sun__ /* somehow solaris is braidamaged in wrt ifr_mtu */ h_if_mtu = ifr.ifr_metric; #else h_if_mtu = ifr.ifr_mtu; #endif } close(fd); return 0; } /* interface not found, use 'lo' */ strlcpy(ifname, "lo", 1024); if(ifstraddr[0] == 0) { if(opt_ipv6) strcpy(ifstraddr, "::1"); else strcpy(ifstraddr, "127.0.0.1"); } h_if_mtu = 1500; close(fd); return 0; } #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \ defined(__bsdi__) || defined(__APPLE__) /* return interface informations : - from the specified (-I) interface - from the routing table - or at least from the first UP interface found */ int get_if_name(void) { /* variable declarations */ struct ifaddrs *ifap, *ifa; char current_if_name[24]; char saved_ifname[24]; struct SOCKADDR output_if_addr; char tmp[1024]; #ifdef __NetBSD__ int s; struct ifreq ifr; #endif /* __NetBSD__ */ if (getifaddrs(&ifap) < 0) perror("getifaddrs"); saved_ifname[0] = 0; /* lookup desired interface */ if(ifname[0] == 0) { /* find gateway interface from kernel */ if (get_output_if(&remote, &output_if_addr) == 0) { if (opt_debug) printf("DEBUG: Output interface address: %s\n", inet_ntop(opt_af, ADDR(&output_if_addr), tmp, sizeof(tmp))); /* Put something in saved_ifname in order to tell that the output adress is known */ saved_ifname[0] = 'X'; saved_ifname[1] = 0; } else { fprintf(stderr, "Warning: Unable to guess the output " "interface\n"); } } else { /* use the forced interface name */ strlcpy(saved_ifname,ifname,24); } /* get interface information */ for (ifa = ifap; ifa; ifa = ifa->ifa_next) { if (opt_debug) printf("\n DEBUG: if %s: ", ifa->ifa_name); /* print if the data structure is null or not */ if (ifa->ifa_data) { if(opt_debug) printf("DEBUG: (struct DATA) "); } else if(opt_debug) printf("DEBUG: (struct DATA is NULL) "); if (!(ifa->ifa_flags & IFF_UP)) { /* if down */ if (opt_debug) printf("DEBUG: DOWN"); continue; } if ((ifa->ifa_flags & IFF_LOOPBACK)&& (strncmp(saved_ifname,"lo0",3))) { /* if loopback */ if (opt_debug) printf("DEBUG: LOOPBACK, SKIPPED"); continue; } if (ifa->ifa_addr->sa_family == AF_LINK) { if (opt_debug) printf("DEBUG: AF_LINK "); strlcpy(ifname,ifa->ifa_name,1024); strlcpy(current_if_name,ifa->ifa_name,24); /* I don't know why NetBSD behavior is not the same */ #ifdef __NetBSD__ memset( &ifr, 0, sizeof(ifr)); strlcpy(ifr.ifr_name, ifa->ifa_name, sizeof(ifr.ifr_name)); if( sizeof(ifr.ifr_addr) >= ifa->ifa_addr->sa_len ) memcpy(&ifr.ifr_addr, ifa->ifa_addr, ifa->ifa_addr->sa_len); if( (s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { perror("[get_if_name] socket"); return -1; } if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) < 0) h_if_mtu = 0; else h_if_mtu = ifr.ifr_mtu; close(s); #else if( ifa->ifa_data ) h_if_mtu = ((struct if_data *)ifa->ifa_data)->ifi_mtu; else { h_if_mtu = 1500; fprintf(stderr, "Warning: fixing MTU to 1500 !\n"); } #endif /* __NetBSD__ */ continue; } if (ifa->ifa_addr->sa_family == AF_INET6) { if (opt_debug) printf("AF_INET6 "); continue; } if (ifa->ifa_addr->sa_family == AF_INET) { if (opt_debug) printf("AF_INET "); if(strncmp(ifa->ifa_name,current_if_name,24)) continue; /* error */ if(opt_debug) printf("OK\n"); strlcpy(ifname,ifa->ifa_name,1024); strlcpy(ifstraddr, inet_ntoa(((struct sockaddr_in *)ifa->ifa_addr)->sin_addr), 1024); if( (saved_ifname[0] == 0) || (!strncmp(ifa->ifa_name, saved_ifname, 24)) || (((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr == output_if_addr.sin_addr.s_addr) ) break; /* asked if found or first UP interface */ } /* interface not found, use hardcoded 'lo' */ strlcpy(ifname, "lo0", 1024); strlcpy(ifstraddr, "127.0.0.1", 1024); h_if_mtu = 1500; } freeifaddrs(ifap); return 0; } #endif /* __*BSD__ */ /* Try to obtain the IP address of the output interface according * to the OS routing table. Derived from R.Stevens */ int get_output_if(struct SOCKADDR *dest, struct SOCKADDR *ifip) { int sock_rt, on=1; struct SOCKADDR iface_out; unsigned int len; if(opt_ipv6) len = sizeof(struct sockaddr_in6); else len = sizeof(struct sockaddr_in); memset(&iface_out, 0, sizeof(iface_out)); sock_rt = socket(opt_af, SOCK_DGRAM, 0); // dest->sin_port = htons(11111); if (setsockopt(sock_rt, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) == -1) { if (opt_debug) perror("DEBUG: [get_output_if] setsockopt(SOL_SOCKET, " "SO_BROADCAST"); close(sock_rt); return -1; } if (connect(sock_rt, (struct sockaddr*)dest, len) == -1 ) { if (opt_debug) perror("DEBUG: [get_output_if] connect"); close(sock_rt); return -1; } if (getsockname(sock_rt, (struct sockaddr *)&iface_out, &len) == -1 ) { if (opt_debug) perror("DEBUG: [get_output_if] getsockname"); close(sock_rt); return -1; } close(sock_rt); // if (iface_out.sin_addr.s_addr == 0) // return 1; memcpy(ifip, &iface_out, len); return 0; }