util-vserver 0.30.215.
[util-vserver.git] / src / naddress.c
index c459dfb..04a6ba2 100644 (file)
@@ -1,4 +1,4 @@
-// $Id: naddress.c 2584 2007-08-10 15:28:42Z dhozac $
+// $Id: naddress.c 2668 2008-01-21 14:13:52Z dhozac $
 
 // Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
 // Copyright (C) 2006 Daniel Hokka Zakrisson <daniel@hozac.com>
@@ -237,94 +237,98 @@ maskToPrefix(void *data, int limit)
   return prefix;
 }
 
-static void
-readIP(char const *str, struct vc_ips **ips, uint16_t type)
+static int
+parseIPFormat(char const *str_c, struct vc_ips **ips,
+            char const *format)
 {
-  if (ifconfig_getaddr(str, &(*ips)->a.vna_v4_ip.s_addr, &(*ips)->a.vna_v4_mask.s_addr, NULL)==-1) {
-    char               *pt;
-    char               tmpopt[strlen(str)+1];
+  size_t len = strlen(str_c);
+  char const *fc;
+  char str[len + 1], *ptr = str;
+  int ret = 0;
+
+  strcpy(str, str_c);
+
+  /* XXX: condition at the bottom */
+  for (fc = format; ; fc += 2) {
+    char *sep;
+    void *dst;
+    unsigned long limit = 0;
+
+    switch (*fc) {
+      case '1': dst = &(*ips)->a.s.ip;         break;
+      case '2': dst = &(*ips)->a.s.ip2;                break;
+      case 'm':        dst = &(*ips)->a.s.mask;        break;
+      default:                                 goto out;
+    }
 
-    strcpy(tmpopt,str);
-    pt = strchr(tmpopt,'/');
-    if (pt)
-      *pt++ = '\0';
+    if (len == 0)
+      goto out;
+    if ((sep = memchr(ptr, *(fc + 1), len)) == NULL)
+      sep = ptr + len;
+    *sep = '\0';
 
-    if (convertAddress(tmpopt, &(*ips)->a.vna_type, &(*ips)->a.vna_v4_ip.s_addr) == -1) {
-      WRITE_MSG(2, "Invalid IP number '");
-      WRITE_STR(2, tmpopt);
-      WRITE_MSG(2, "'\n");
-      exit(wrapper_exit_code);
+    /* This is ugly, and means that m cannot be first */
+    switch ((*ips)->a.vna_type) {
+      case VC_NXA_TYPE_IPV4: limit =  32;      break;
+      case VC_NXA_TYPE_IPV6: limit = 128;      break;
     }
 
-    if (pt==0) {
+    /* This is required due to the dain-bramage that is inet_pton in dietlibc.
+     * Essentially any number will be parsed as a valid IPv4 address...
+     */
+    if (*fc == 'm' && strchr(ptr, ':') == NULL && strchr(ptr, '.') == NULL) {
+      /* This is a prefix, not a netmask */
+      unsigned long    sz;
+
+      if (!isNumberUnsigned(ptr, &sz, true) || sz > limit) {
+       ret = -1;
+       goto out;
+      }
+
+      (*ips)->a.vna_prefix = sz;
       switch ((*ips)->a.vna_type) {
        case VC_NXA_TYPE_IPV4:
-         (*ips)->a.vna_v4_mask.s_addr = htonl(0xffffff00);
-         (*ips)->a.vna_prefix = 24;
+         (*ips)->a.vna_v4_mask.s_addr = htonl(~((1 << (32 - sz)) - 1));
          break;
        case VC_NXA_TYPE_IPV6:
-         (*ips)->a.vna_prefix = 64;
-         (*ips)->a.vna_v6_mask.s6_addr32[0] = (*ips)->a.vna_v6_mask.s6_addr32[1] = 0xffffffff;
-         (*ips)->a.vna_v6_mask.s6_addr32[2] = (*ips)->a.vna_v6_mask.s6_addr32[3] = 0x00000000;
+         ipv6PrefixToMask(&(*ips)->a.vna_v6_mask, sz);
          break;
-       default: break;
       }
     }
     else {
-      // Ok, we have a network size, not a netmask
-      if (strchr(pt,'.')==0 && strchr(pt,':')==0) {
-       unsigned long   sz, limit = 0;
-
-       switch ((*ips)->a.vna_type) {
-         case VC_NXA_TYPE_IPV4: limit =  32;   break;
-         case VC_NXA_TYPE_IPV6: limit = 128;   break;
-         default:                              break;
-       }
-
-       if (!isNumberUnsigned(pt, &sz, true) || sz > limit) {
-         WRITE_MSG(2, "Invalid prefix '");
-         WRITE_STR(2, pt);
-         WRITE_MSG(2, "'\n");
-         exit(wrapper_exit_code);
-       }
-
-       (*ips)->a.vna_prefix = sz;
-       switch ((*ips)->a.vna_type) {
-         case VC_NXA_TYPE_IPV4:
-           (*ips)->a.vna_v4_mask.s_addr = htonl(~((1 << (32 - sz)) - 1));
-           break;
-         case VC_NXA_TYPE_IPV6:
-           ipv6PrefixToMask(&(*ips)->a.vna_v6_mask, (*ips)->a.vna_prefix);
-           break;
-         default: break;
-       }
+      if (convertAddress(ptr, &(*ips)->a.vna_type, dst) == -1) {
+       ret = -1;
+       goto out;
       }
-      else {
-       int af, limit;
-       void *mask;
-       switch ((*ips)->a.vna_type) {
-         case VC_NXA_TYPE_IPV4:
-           af = AF_INET;
-           mask = &(*ips)->a.vna_v4_mask.s_addr;
-           limit = 32;
-           break;
-         case VC_NXA_TYPE_IPV6:
-           af = AF_INET6;
-           mask = (*ips)->a.vna_v6_mask.s6_addr32;
-           limit = 128;
-           break;
-         default:
-           return;
-       }
-       if (inet_pton(af, pt, mask) < 0) {
-         WRITE_MSG(2, "Invalid netmask '");
-         WRITE_STR(2, pt);
-         WRITE_MSG(2, "'\n");
-         exit(wrapper_exit_code);
-       }
-       (*ips)->a.vna_prefix = maskToPrefix(mask, limit);
+      else if (*fc == 'm') {
+       /* Got a mask, set the prefix */
+       (*ips)->a.vna_prefix = maskToPrefix(&(*ips)->a.s.mask, limit);
       }
     }
+
+    ret++;
+    len -= (sep - ptr);
+    ptr = sep + 1;
+
+    if (*(fc + 1) == '\0')
+      break;
+  }
+
+out:
+  free(str);
+  return ret;
+}
+
+static void
+readIP(char const *str, struct vc_ips **ips, uint16_t type)
+{
+  if (ifconfig_getaddr(str, &(*ips)->a.vna_v4_ip.s_addr, &(*ips)->a.vna_v4_mask.s_addr, NULL)==-1) {
+    if (parseIPFormat(str, ips, "1/m") < 1) {
+      WRITE_MSG(2, "Invalid IP number '");
+      WRITE_STR(2, str);
+      WRITE_MSG(2, "'\n");
+      exit(wrapper_exit_code);
+    }
   }
   else
     (*ips)->a.vna_type = VC_NXA_TYPE_IPV4;
@@ -352,6 +356,20 @@ readBcast(char const *str, struct vc_ips **ips)
   *ips = (*ips)->next;
 }
 
+static void
+readRange(char const *str, struct vc_ips **ips)
+{
+  if (parseIPFormat(str, ips, "1-2/m") < 2) {
+    WRITE_MSG(2, "Invalid range '");
+    WRITE_STR(2, str);
+    WRITE_MSG(2, "'\n");
+    exit(wrapper_exit_code);
+  }
+  (*ips)->a.vna_type |= VC_NXA_TYPE_RANGE;
+  (*ips)->next = calloc(1, sizeof(struct vc_ips));
+  *ips = (*ips)->next;
+}
+
 static void
 tellAddress(struct vc_net_addr *addr, bool silent)
 {
@@ -452,7 +470,7 @@ int main (int argc, char *argv[])
       case CMD_SET     :  args.do_set    = true; break;
       case CMD_IP      :  readIP(optarg, &ips, VC_NXA_TYPE_ADDR);  break;
       case CMD_MASK    :  readIP(optarg, &ips, VC_NXA_TYPE_MASK);  break;
-      case CMD_RANGE   :  readIP(optarg, &ips, VC_NXA_TYPE_RANGE); break;
+      case CMD_RANGE   :  readRange(optarg, &ips); break;
       case CMD_BCAST   :  readBcast(optarg, &ips); break;
       case CMD_LBACK   :  readIP(optarg, &ips, VC_NXA_TYPE_ADDR | VC_NXA_MOD_LBACK); break;
       default          :