X-Git-Url: http://git.linux-vserver.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fnaddress.c;h=fb6fdfe9c6212480f60d0204402f6962237c3369;hb=HEAD;hp=0d1efc10607bae21dbb9b1135d45ac592c1a5b9d;hpb=e97918417e2f91e76024bee546366f2f0d43c281;p=util-vserver.git diff --git a/src/naddress.c b/src/naddress.c index 0d1efc1..fb6fdfe 100644 --- a/src/naddress.c +++ b/src/naddress.c @@ -54,8 +54,12 @@ #define CMD_NID 0x2001 #define CMD_ADD 0x2002 #define CMD_REMOVE 0x2003 +#define CMD_SET 0x2004 #define CMD_IP 0x2010 #define CMD_BCAST 0x2011 +#define CMD_MASK 0x2012 +#define CMD_RANGE 0x2013 +#define CMD_LBACK 0x2014 int wrapper_exit_code = 255; @@ -67,14 +71,18 @@ CMDLINE_OPTIONS[] = { { "silent", no_argument, 0, CMD_SILENT }, { "add", no_argument, 0, CMD_ADD }, { "remove", no_argument, 0, CMD_REMOVE }, + { "set", no_argument, 0, CMD_SET }, { "nid", required_argument, 0, CMD_NID }, { "ip", required_argument, 0, CMD_IP }, + { "mask", required_argument, 0, CMD_MASK }, + { "range", required_argument, 0, CMD_RANGE }, { "bcast", required_argument, 0, CMD_BCAST }, + { "lback", required_argument, 0, CMD_LBACK }, { 0,0,0,0 } }; struct vc_ips { - struct vc_net_nx a; + struct vc_net_addr a; struct vc_ips *next; }; @@ -84,6 +92,7 @@ struct Arguments { bool is_silent; bool do_add; bool do_remove; + bool do_set; }; static void @@ -92,7 +101,8 @@ showHelp(int fd, char const *cmd, int res) WRITE_MSG(fd, "Usage:\n "); WRITE_STR(fd, cmd); WRITE_MSG(fd, - " [--silent] [--nid ] [--ip [/]] [--bcast ] [--] *\n\n" + " (--add|--remove|--set) [--silent] [--nid ]\n" + " [--ip [/]] [--bcast ] [--] *\n\n" "Please report bugs to " PACKAGE_BUGREPORT "\n"); exit(res); @@ -193,77 +203,136 @@ int ifconfig_getaddr ( } static int -convertAddress(const char *str, vc_net_nx_type *type, void *dst) +convertAddress(const char *str, uint16_t *type, void *dst) { int ret; - if (type) *type = vcNET_IPV4; + if (type) *type = VC_NXA_TYPE_IPV4; ret = inet_pton(AF_INET, str, dst); if (ret==0) { - if (type) *type = vcNET_IPV6; + if (type) *type = VC_NXA_TYPE_IPV6; ret = inet_pton(AF_INET6, str, dst); } return ret > 0 ? 0 : -1; } static void -readIP(char const *str, struct vc_ips **ips) +ipv6PrefixToMask(struct in6_addr *mask, int prefix) { - if (ifconfig_getaddr(str, &(*ips)->a.ip[0], &(*ips)->a.mask[0], NULL)==-1) { - char *pt; - char tmpopt[strlen(str)+1]; - uint32_t *mask = (*ips)->a.mask; + int i; + mask->s6_addr32[0] = mask->s6_addr32[1] = mask->s6_addr32[2] = mask->s6_addr32[3] = 0; + for (i = 0; (i << 3) < prefix; i++) { + mask->s6_addr[i] = 0xff; + } + if ((i << 3) > prefix) + mask->s6_addr[i-1] = ~((1 << (prefix & 0x07)) - 1); +} - strcpy(tmpopt,str); - pt = strchr(tmpopt,'/'); - if (pt) - *pt++ = '\0'; +static int +maskToPrefix(void *data, int limit) +{ + uint8_t *mask = data; + int prefix; + for (prefix = 0; prefix < limit && mask[prefix >> 3] & (1 << (prefix & 0x07)); prefix++) + ; + return prefix; +} - if (convertAddress(tmpopt, &(*ips)->a.type, (*ips)->a.ip) == -1) { - WRITE_MSG(2, "Invalid IP number '"); - WRITE_STR(2, tmpopt); - WRITE_MSG(2, "'\n"); - exit(wrapper_exit_code); +static int +parseIPFormat(char const *str_c, struct vc_ips **ips, + char const *format) +{ + 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; + } + + if (len == 0) + goto out; + if ((sep = memchr(ptr, *(fc + 1), len)) == NULL) + sep = ptr + len; + *sep = '\0'; + + /* 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) { - switch ((*ips)->a.type) { - case vcNET_IPV4: - mask[0] = htonl(0xffffff00); + /* 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(~((1 << (32 - sz)) - 1)); break; - case vcNET_IPV6: - mask[0] = 64; + case VC_NXA_TYPE_IPV6: + 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) { - int sz = atoi(pt); - switch ((*ips)->a.type) { - case vcNET_IPV4: - mask[0] = htonl((1 << sz) - 1); - break; - case vcNET_IPV6: - mask[0] = sz; - break; - default: break; - } + if (convertAddress(ptr, &(*ips)->a.vna_type, dst) == -1) { + ret = -1; + goto out; } - else { - if (convertAddress(pt, NULL, &(*ips)->a.mask) == -1) { - WRITE_MSG(2, "Invalid netmask '"); - WRITE_STR(2, pt); - WRITE_MSG(2, "'\n"); - exit(wrapper_exit_code); - } + 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: + 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.type = vcNET_IPV4; + (*ips)->a.vna_type = VC_NXA_TYPE_IPV4; + (*ips)->a.vna_type |= type; - (*ips)->a.count = 1; (*ips)->next = calloc(1, sizeof(struct vc_ips)); *ips = (*ips)->next; } @@ -273,28 +342,55 @@ readBcast(char const *str, struct vc_ips **ips) { uint32_t bcast; if (ifconfig_getaddr(str, NULL, NULL, &bcast)==-1){ - if (convertAddress(str, NULL, &bcast) == -1) { + if (inet_pton(AF_INET, str, &bcast) < 0) { WRITE_MSG(2, "Invalid broadcast number '"); WRITE_STR(2, optarg); WRITE_MSG(2, "'\n"); exit(wrapper_exit_code); } } - (*ips)->a.ip[0] = bcast; - (*ips)->a.count = 1; - (*ips)->a.type = vcNET_IPV4B; + (*ips)->a.vna_v4_ip.s_addr = bcast; + (*ips)->a.vna_type = VC_NXA_TYPE_IPV4 | VC_NXA_MOD_BCAST | VC_NXA_TYPE_ADDR; + (*ips)->next = calloc(1, sizeof(struct vc_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_nx *addr, bool silent) +tellAddress(struct vc_net_addr *addr, bool silent) { char buf[41]; + int af; + void *address; if (silent) return; - if (inet_ntop(addr->type == vcNET_IPV6 ? AF_INET6 : AF_INET, - &addr->ip, buf, sizeof(buf)) == NULL) { + switch (addr->vna_type & (VC_NXA_TYPE_IPV4 | VC_NXA_TYPE_IPV6)) { + case VC_NXA_TYPE_IPV4: + af = AF_INET; + address = &addr->vna_v4_ip.s_addr; + break; + case VC_NXA_TYPE_IPV6: + af = AF_INET6; + address = addr->vna_v6_ip.s6_addr32; + break; + default: + WRITE_MSG(1, " "); + return; + } + if (inet_ntop(af, address, buf, sizeof(buf)) == NULL) { WRITE_MSG(1, " "); return; } @@ -306,12 +402,23 @@ static inline void doit(struct Arguments *args) { struct vc_ips *ips; - if (args->do_add) { + + if (args->do_set) { + struct vc_net_addr remove = { .vna_type = VC_NXA_TYPE_ANY }; + if (vc_net_remove(args->nid, &remove) == -1) { + perror(ENSC_WRAPPERS_PREFIX "vc_net_remove()"); + exit(wrapper_exit_code); + } + } + + if (args->do_add || args->do_set) { if (!args->is_silent) WRITE_MSG(1, "Adding"); for (ips = &args->head; ips->next; ips = ips->next) { tellAddress(&ips->a, args->is_silent); - if (vc_net_add(args->nid, &ips->a) != (int)ips->a.count) { + if (vc_net_add(args->nid, &ips->a) == -1) { + if (!args->is_silent) + WRITE_MSG(1, "\n"); perror(ENSC_WRAPPERS_PREFIX "vc_net_add()"); exit(wrapper_exit_code); } @@ -324,7 +431,9 @@ doit(struct Arguments *args) WRITE_MSG(1, "Removing"); for (ips = &args->head; ips->next; ips = ips->next) { tellAddress(&ips->a, args->is_silent); - if (vc_net_remove(args->nid, &ips->a) != (int)ips->a.count) { + if (vc_net_remove(args->nid, &ips->a) == -1) { + if (!args->is_silent) + WRITE_MSG(1, "\n"); perror(ENSC_WRAPPERS_PREFIX "vc_net_remove()"); exit(wrapper_exit_code); } @@ -341,6 +450,7 @@ int main (int argc, char *argv[]) .is_silent = false, .do_add = false, .do_remove = false, + .do_set = false, .head = { .next = NULL }, }; struct vc_ips *ips = &args.head; @@ -350,18 +460,22 @@ int main (int argc, char *argv[]) if (c==-1) break; switch (c) { - case CMD_HELP : showHelp(1, argv[0], 0); - case CMD_VERSION : showVersion(); - case CMD_SILENT : args.is_silent = true; break; - case CMD_BCAST : readBcast(optarg, &ips); break; - case CMD_NID : args.nid = Evc_nidopt2nid(optarg,true); break; - case CMD_ADD : args.do_add = true; break; - case CMD_REMOVE : args.do_remove = true; break; - case CMD_IP : readIP(optarg, &ips); break; + case CMD_HELP : showHelp(1, argv[0], 0); + case CMD_VERSION : showVersion(); + case CMD_SILENT : args.is_silent = true; break; + case CMD_NID : args.nid = Evc_nidopt2nid(optarg,true); break; + case CMD_ADD : args.do_add = true; break; + case CMD_REMOVE : args.do_remove = true; break; + 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 : 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 : WRITE_MSG(2, "Try '"); WRITE_STR(2, argv[0]); - WRITE_MSG(2, " --help\" for more information.\n"); + WRITE_MSG(2, " --help' for more information.\n"); exit(wrapper_exit_code); break; } @@ -369,11 +483,11 @@ int main (int argc, char *argv[]) if (args.nid == VC_NOCTX) args.nid = Evc_get_task_nid(0); - if (!args.do_add && !args.do_remove) { + if (!args.do_add && !args.do_remove && !args.do_set) { WRITE_MSG(2, "No operation specified; try '--help' for more information\n"); exit(wrapper_exit_code); } - else if (args.do_add && args.do_remove) { + else if (((args.do_add ? 1 : 0) + (args.do_remove ? 1 : 0) + (args.do_set ? 1 : 0)) > 1) { WRITE_MSG(2, "Multiple operations specified; try '--help' for more information\n"); exit(wrapper_exit_code); }