/* 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_in *dest, struct sockaddr_in *ifip); #if (defined OSTYPE_LINUX) || (defined __sun__) int get_if_name(void) { int fd; struct ifconf ifc; struct ifreq ibuf[16], ifr, *ifrp, *ifend; struct sockaddr_in sa; struct sockaddr_in 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; if (opt_debug) printf("DEBUG: Output interface address: %s\n", inet_ntoa(sa.sin_addr)); } else { fprintf(stderr, "Warning: Unable to guess the output " "interface\n"); } } if ( (fd = socket(AF_INET, 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; /* 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 */ ifrp = ibuf; ifend = (struct ifreq*) ((char*)ibuf + ifc.ifc_len); for (; ifrp < ifend; ifrp++) { strlcpy(ifr.ifr_name, ifrp->ifr_name, 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 (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 locking for */ if (sa.sin_addr.s_addr != 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 ( 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)); strlcpy(ifstraddr, inet_ntoa(sa.sin_addr), 1024); /* 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); strlcpy(ifstraddr, "127.0.0.1", 1024); 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_in output_if_addr; #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_ntoa(output_if_addr.sin_addr)); /* 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_in *dest, struct sockaddr_in *ifip) { int sock_rt, len, on=1; struct sockaddr_in iface_out; memset(&iface_out, 0, sizeof(iface_out)); sock_rt = socket(AF_INET, 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, sizeof(struct sockaddr_in)) == -1 ) { if (opt_debug) perror("DEBUG: [get_output_if] connect"); close(sock_rt); return -1; } len = sizeof(iface_out); 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, sizeof(struct sockaddr_in)); return 0; }