/* Create/manage IP aliases maping long name to short name to please the limitation of the kernel. The short names all start with V. The program use the file /var/run/vipaliases to store the name. The name at line 5 correspond to V5 and so on. vipalias set name ip netmask broadcast vipalias unset name vipalias list */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; static const char *statefile = "/var/run/vipaliases"; static const char *lockfile = "/var/run/vipaliases.lock"; static void usage() { fprintf (stderr,"vipalias version %s\n",VERSION); fprintf (stderr, "\n" "vipalias set device name ip netmask broadcast\n" "vipalias unset device name\n" "vipalias list\n"); } #include "vipalias.lock.h" static int vipalias_find (vector &tb, const char *name) { int ret = -1; for (vector::iterator it = tb.begin(); it != tb.end(); it++){ if (strcmp(it->c_str(),name)==0){ ret = it - tb.begin(); break; } } return ret; } static void vipalias_read (vector &tb) { FILE *fin = fopen (statefile,"r"); if (fin != NULL){ char line[1000]; while (fgets(line,sizeof(line)-1,fin)!=NULL){ char *pt = strchr(line,'\n'); if (pt != NULL) *pt = '\0'; if (line[0] > ' '){ tb.push_back(line); } } fclose (fin); } } static void vipalias_write (vector &tb) { FILE *fout = fopen (statefile,"w"); if (fout != NULL){ for (vector::iterator it = tb.begin(); it != tb.end(); it++){ fprintf (fout,"%s\n",it->c_str()); } fclose (fout); } } static void ipnum_ip2a(unsigned long ip, char *buf) { sprintf (buf,"%u.%u.%u.%u" ,(unsigned)(ip >> 24) ,(unsigned)((ip >> 16 ) & 0xff) ,(unsigned)((ip >> 8 ) & 0xff) ,(unsigned)(ip & 0xff)); } 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 void ifconfig_format (struct sockaddr &adr, char *buf) { struct sockaddr_in *sin = (struct sockaddr_in*)&adr; ipnum_ip2a (htonl(sin->sin_addr.s_addr),buf); } static int ifconfig_getinfo ( const char *ifname, char ip[20], char mask[20], char bcast[20]) { int ret = -1; strcpy (ip,"0.0.0.0"); strcpy (mask,"0.0.0.0"); strcpy (bcast,"0.0.0.0"); int skfd = socket(AF_INET, SOCK_DGRAM, 0); if (skfd != -1){ struct ifreq ifr; if (ifconfig_ioctl(skfd, ifname, SIOCGIFFLAGS, ifr) >= 0){ ret = 0; if (ifconfig_ioctl(skfd,ifname,SIOCGIFADDR, ifr) >= 0){ ifconfig_format (ifr.ifr_addr,ip); if (ifconfig_ioctl(skfd, ifname,SIOCGIFNETMASK, ifr) >= 0) { ifconfig_format (ifr.ifr_netmask,mask); if (ifconfig_ioctl(skfd, ifname,SIOCGIFBRDADDR, ifr) >= 0) { ifconfig_format (ifr.ifr_broadaddr,bcast); } } } } close (skfd); } return ret; } /* Read all the aliases, find the DEV:Vnn ones, and map nn to DEV */ static void devlist_read( map &v2dev) { int ret = -1; int skfd = socket (AF_INET,SOCK_DGRAM,0); if (skfd < 0) { perror ("socket"); }else{ struct ifconf ifc; int numreqs = 30; ifc.ifc_buf = NULL; ret = 0; while (1) { ifc.ifc_len = sizeof(struct ifreq) * numreqs; ifc.ifc_buf = (char*)realloc(ifc.ifc_buf, ifc.ifc_len); if (ioctl(skfd, SIOCGIFCONF, &ifc) < 0) { perror("SIOCGIFCONF"); ret = -1; break; } if (ifc.ifc_len == (int)sizeof(struct ifreq) * numreqs) { /* assume it overflowed and try again */ numreqs += 10; continue; } break; } if (ret == 0){ struct ifreq *ifr = ifc.ifc_req; for (int n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq)) { const char *name = ifr->ifr_name; const char *pt = strchr(name,':'); if (pt != NULL && pt[1] == 'V' && isdigit(pt[2])){ int pos = atoi(pt+2); string dev(name,pt); v2dev[pos] = dev; } ifr++; } } free(ifc.ifc_buf); } } int main (int argc, char *argv[]) { int ret = -1; vector tb; if (argc == 7 && strcmp(argv[1],"set")==0){ const char *device = argv[2]; const char *name = argv[3]; const char *ip = argv[4]; const char *mask = argv[5]; const char *bcast = argv[6]; if (vipalias_lock() != -1){ vipalias_read(tb); int pos = vipalias_find (tb,name); if (pos == -1){ pos = vipalias_find(tb,"-"); if (pos != -1){ tb[pos] = name; }else{ pos = tb.size(); tb.push_back(name); } vipalias_write (tb); } char tmp[200]; snprintf (tmp,sizeof(tmp)-1 ,"/sbin/ifconfig %s:V%d %s netmask %s broadcast %s" ,device,pos,ip,mask,bcast); ret = system(tmp); vipalias_unlock(); } }else if (argc == 4 && strcmp(argv[1],"unset")==0){ const char *device = argv[2]; const char *name = argv[3]; if (vipalias_lock() != -1){ vipalias_read(tb); int pos = vipalias_find (tb,name); if (pos != -1){ tb[pos] = "-"; char tmp[100]; snprintf (tmp,sizeof(tmp)-1,"/sbin/ifconfig %s:V%d down" ,device,pos); ret = system(tmp); vipalias_write (tb); } vipalias_unlock(); } }else if ((argc == 2 || argc == 3) && strcmp(argv[1],"list")==0){ if (vipalias_lock() != -1){ vipalias_read(tb); map mp; for (vector::iterator it=tb.begin(); it != tb.end(); it++){ if (strcmp(it->c_str(),"-")!=0){ mp[*it] = it - tb.begin(); } } map v2dev; devlist_read (v2dev); if (argc == 3){ // List the IP of one vserver bool found = false; for (map::iterator it=mp.begin(); it != mp.end(); it++){ const char *key = it->first.c_str(); key = strchr(key,'-'); if (key != NULL && strcmp(argv[2],key+1)==0){ int pos = it->second; const char *device = v2dev[pos].c_str(); char tmp[100],ip[20],mask[20],bcast[20]; snprintf (tmp,sizeof(tmp)-1,"%s:V%u",device,pos); ifconfig_getinfo (tmp,ip,mask,bcast); printf ("%s\t%s\n",ip,mask); found = true; } } if (!found){ fprintf (stderr,"No IP defined for vserver %s\n",argv[2]); } }else{ for (map::iterator it=mp.begin(); it != mp.end(); it++){ int pos = it->second; const char *device = v2dev[pos].c_str(); char tmp[100],ip[20],mask[20],bcast[20]; snprintf (tmp,sizeof(tmp)-1,"%s:V%u",device,pos); ifconfig_getinfo (tmp,ip,mask,bcast); char ali[100],ipmask[100]; snprintf (ali,sizeof(ali)-1,"%s:V%d",device,pos); snprintf (ipmask,sizeof(ipmask)-1,"%s/%s",ip,mask); printf ("%-10s %-30s %s\n",ali,ipmask,it->first.c_str()); } } vipalias_unlock(); } }else{ usage(); } return ret; }