/* Prints the specs of a network device in shell like form ADDR= NETMASK= BCAST= */ #include #include #include #include #include #include #include #include #include static void usage() { fprintf (stderr,"ifspec version %s\n",VERSION); fprintf (stderr ,"ifspec network-device [ ipaddr netmask broadcast ]\n" "prints device specification in a shell usable way\n"); exit (-1); } static bool all_digit(const char *s) { const char *start = s; while (isdigit(*s)) s++; return s > start && *s == '\0'; } static int ifconfig_ioctl( int fd, const char *ifname, int cmd, struct ifreq *ifr) { strcpy(ifr->ifr_name, ifname); return ioctl(fd, cmd,ifr); } static unsigned long ip_cnv (const char *str) { const char *start_str = str; unsigned tb[4]; memset (tb,-1,sizeof(tb)); int no = 0; while (*str != '\0' && no < 4){ if (isdigit(*str)){ int val = atoi(str); if (val > 255) break; tb[no++] = val; while (isdigit(*str)) str++; if (*str == '.'){ str++; }else{ break; } }else{ break; } } unsigned long ret = (tb[0] << 24) | (tb[1]<<16) | (tb[2] << 8) | tb[3]; if (no != 4 || *str != '\0'){ fprintf (stderr,"Invalid IP number or netmask: %s\n",start_str); ret = 0xffffffff; } return ret; } /* Print an IP number with a variable assigned (VAR=x.y.z.w) */ static void ifspec_printip (const char *varname, unsigned long addr) { printf ("%s=%lu.%lu.%lu.%lu\n" ,varname ,(addr>>24)&0xff ,(addr>>16)&0xff ,(addr>>8)&0xff ,addr&0xff); } /* Fetch the IP number of an interface from the kernel. Assume the device is already available in the kernel Return -1 if any error. */ int ifconfig_print ( const char *ifname, const char *addrstr, const char *maskstr, const char *bcaststr) { int ret = -1; int skfd = socket(AF_INET, SOCK_DGRAM, 0); if (skfd != -1){ struct ifreq ifr; struct { unsigned long addr; unsigned long mask; } solved = {0xffffffff,0xffffffff}; if (addrstr != NULL && addrstr[0] != '\0'){ printf ("ADDR=%s\n",addrstr); solved.addr = ip_cnv (addrstr); }else if (ifconfig_ioctl(skfd,ifname,SIOCGIFADDR, &ifr) >= 0){ struct sockaddr_in *sin = (struct sockaddr_in*)&ifr.ifr_addr; solved.addr = ntohl(sin->sin_addr.s_addr); ifspec_printip ("ADDR",solved.addr); ret = 0; } bool gotmask = false; if (maskstr != NULL && maskstr[0] != '\0'){ gotmask = true; if (all_digit(maskstr)){ solved.mask = 0xffffffff; int n = atoi(maskstr); for (int i=n; i<32; i++) solved.mask <<= 1; }else{ solved.mask = ip_cnv (maskstr); } }else if (ifconfig_ioctl(skfd,ifname,SIOCGIFNETMASK, &ifr) >= 0){ struct sockaddr_in *sin = (struct sockaddr_in*)&ifr.ifr_addr; solved.mask = ntohl(sin->sin_addr.s_addr); } ifspec_printip ("NETMASK",solved.mask); if (bcaststr != NULL && bcaststr[0] != '\0'){ printf ("BCAST=%s\n",bcaststr); }else if (!gotmask && ifconfig_ioctl(skfd,ifname,SIOCGIFBRDADDR, &ifr) >= 0){ struct sockaddr_in *sin = (struct sockaddr_in*)&ifr.ifr_addr; unsigned long bcast = ntohl(sin->sin_addr.s_addr); ifspec_printip ("BCAST",bcast); }else{ // Can't get it from the kernel, compute it from the IP // and the netmask unsigned long bcast = (solved.addr & solved.mask) | ~solved.mask; ifspec_printip ("BCAST",bcast); } close (skfd); } return ret; } int main (int argc, char *argv[]) { int ret = -1; if (argc < 2){ usage(); }else{ const char *addrstr = argc >= 3 ? argv[2] : NULL; const char *maskstr = argc >= 4 ? argv[3] : NULL; const char *bcaststr = argc >= 5 ? argv[4] : NULL; ret = ifconfig_print (argv[1],addrstr,maskstr,bcaststr); } return ret; }