diff --git a/include/utils.h b/include/utils.h index d3895d56..f562547d 100644 --- a/include/utils.h +++ b/include/utils.h @@ -54,7 +54,40 @@ typedef struct __u32 data[64]; } inet_prefix; -#define PREFIXLEN_SPECIFIED 1 +enum { + PREFIXLEN_SPECIFIED = (1 << 0), + ADDRTYPE_INET = (1 << 1), + ADDRTYPE_UNSPEC = (1 << 2), + ADDRTYPE_MULTI = (1 << 3), + + ADDRTYPE_INET_UNSPEC = ADDRTYPE_INET | ADDRTYPE_UNSPEC, + ADDRTYPE_INET_MULTI = ADDRTYPE_INET | ADDRTYPE_MULTI +}; + +static inline bool is_addrtype_inet(const inet_prefix *p) +{ + return p->flags & ADDRTYPE_INET; +} + +static inline bool is_addrtype_inet_unspec(const inet_prefix *p) +{ + return (p->flags & ADDRTYPE_INET_UNSPEC) == ADDRTYPE_INET_UNSPEC; +} + +static inline bool is_addrtype_inet_multi(const inet_prefix *p) +{ + return (p->flags & ADDRTYPE_INET_MULTI) == ADDRTYPE_INET_MULTI; +} + +static inline bool is_addrtype_inet_not_unspec(const inet_prefix *p) +{ + return (p->flags & ADDRTYPE_INET_UNSPEC) == ADDRTYPE_INET; +} + +static inline bool is_addrtype_inet_not_multi(const inet_prefix *p) +{ + return (p->flags & ADDRTYPE_INET_MULTI) == ADDRTYPE_INET; +} #define DN_MAXADDL 20 #ifndef AF_DECnet @@ -236,7 +269,6 @@ void print_nlmsg_timestamp(FILE *fp, const struct nlmsghdr *n); extern int cmdlineno; ssize_t getcmdline(char **line, size_t *len, FILE *in); int makeargs(char *line, char *argv[], int maxargs); -int inet_get_addr(const char *src, __u32 *dst, struct in6_addr *dst6); struct iplink_req { struct nlmsghdr n; diff --git a/ip/iplink_geneve.c b/ip/iplink_geneve.c index 2d0a0411..1c28bb9c 100644 --- a/ip/iplink_geneve.c +++ b/ip/iplink_geneve.c @@ -57,9 +57,8 @@ static void check_duparg(__u64 *attrs, int type, const char *key, static int geneve_parse_opt(struct link_util *lu, int argc, char **argv, struct nlmsghdr *n) { + inet_prefix daddr; __u32 vni = 0; - __u32 daddr = 0; - struct in6_addr daddr6 = IN6ADDR_ANY_INIT; __u32 label = 0; __u8 ttl = 0; __u8 tos = 0; @@ -72,6 +71,8 @@ static int geneve_parse_opt(struct link_util *lu, int argc, char **argv, bool set_op = (n->nlmsg_type == RTM_NEWLINK && !(n->nlmsg_flags & NLM_F_CREATE)); + daddr.flags = 0; + while (argc > 0) { if (!matches(*argv, "id") || !matches(*argv, "vni")) { @@ -84,11 +85,8 @@ static int geneve_parse_opt(struct link_util *lu, int argc, char **argv, NEXT_ARG(); check_duparg(&attrs, IFLA_GENEVE_REMOTE, "remote", *argv); - if (!inet_get_addr(*argv, &daddr, &daddr6)) { - fprintf(stderr, "Invalid address \"%s\"\n", *argv); - return -1; - } - if (IN6_IS_ADDR_MULTICAST(&daddr6) || IN_MULTICAST(ntohl(daddr))) + get_addr(&daddr, *argv, AF_UNSPEC); + if (!is_addrtype_inet_not_multi(&daddr)) invarg("invalid remote address", *argv); } else if (!matches(*argv, "ttl") || !matches(*argv, "hoplimit")) { @@ -191,18 +189,17 @@ static int geneve_parse_opt(struct link_util *lu, int argc, char **argv, * ID (VNI) to identify the geneve device, and we do not need * the remote IP. */ - if (!set_op && !daddr && IN6_IS_ADDR_UNSPECIFIED(&daddr6)) { + if (!set_op && !is_addrtype_inet(&daddr)) { fprintf(stderr, "geneve: remote link partner not specified\n"); return -1; } } addattr32(n, 1024, IFLA_GENEVE_ID, vni); - if (daddr) - addattr_l(n, 1024, IFLA_GENEVE_REMOTE, &daddr, 4); - if (!IN6_IS_ADDR_UNSPECIFIED(&daddr6)) { - addattr_l(n, 1024, IFLA_GENEVE_REMOTE6, &daddr6, - sizeof(struct in6_addr)); + if (is_addrtype_inet(&daddr)) { + int type = (daddr.family == AF_INET) ? IFLA_GENEVE_REMOTE : + IFLA_GENEVE_REMOTE6; + addattr_l(n, sizeof(1024), type, daddr.data, daddr.bytelen); } if (!set_op || GENEVE_ATTRSET(attrs, IFLA_GENEVE_LABEL)) addattr32(n, 1024, IFLA_GENEVE_LABEL, label); diff --git a/ip/iplink_vxlan.c b/ip/iplink_vxlan.c index 88b56625..842c3565 100644 --- a/ip/iplink_vxlan.c +++ b/ip/iplink_vxlan.c @@ -74,11 +74,9 @@ static void check_duparg(__u64 *attrs, int type, const char *key, static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv, struct nlmsghdr *n) { + inet_prefix saddr; + inet_prefix daddr; __u32 vni = 0; - __u32 gaddr = 0; - __u32 daddr = 0; - struct in6_addr gaddr6 = IN6ADDR_ANY_INIT; - struct in6_addr daddr6 = IN6ADDR_ANY_INIT; __u8 learning = 1; __u16 dstport = 0; __u8 metadata = 0; @@ -86,6 +84,9 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv, bool set_op = (n->nlmsg_type == RTM_NEWLINK && !(n->nlmsg_flags & NLM_F_CREATE)); + saddr.family = daddr.family = AF_UNSPEC; + saddr.flags = daddr.flags = 0; + while (argc > 0) { if (!matches(*argv, "id") || !matches(*argv, "vni")) { @@ -98,54 +99,33 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv, vni >= 1u << 24) invarg("invalid id", *argv); } else if (!matches(*argv, "group")) { - if (daddr || !IN6_IS_ADDR_UNSPECIFIED(&daddr6)) { + if (is_addrtype_inet_not_multi(&daddr)) { fprintf(stderr, "vxlan: both group and remote"); fprintf(stderr, " cannot be specified\n"); return -1; } NEXT_ARG(); check_duparg(&attrs, IFLA_VXLAN_GROUP, "group", *argv); - if (!inet_get_addr(*argv, &gaddr, &gaddr6)) { - fprintf(stderr, "Invalid address \"%s\"\n", *argv); - return -1; - } - if (!IN6_IS_ADDR_MULTICAST(&gaddr6) && !IN_MULTICAST(ntohl(gaddr))) + get_addr(&daddr, *argv, saddr.family); + if (!is_addrtype_inet_multi(&daddr)) invarg("invalid group address", *argv); } else if (!matches(*argv, "remote")) { - if (gaddr || !IN6_IS_ADDR_UNSPECIFIED(&gaddr6)) { + if (is_addrtype_inet_multi(&daddr)) { fprintf(stderr, "vxlan: both group and remote"); fprintf(stderr, " cannot be specified\n"); return -1; } NEXT_ARG(); check_duparg(&attrs, IFLA_VXLAN_GROUP, "remote", *argv); - if (!inet_get_addr(*argv, &daddr, &daddr6)) { - fprintf(stderr, "Invalid address \"%s\"\n", *argv); - return -1; - } - if (IN6_IS_ADDR_MULTICAST(&daddr6) || IN_MULTICAST(ntohl(daddr))) + get_addr(&daddr, *argv, saddr.family); + if (!is_addrtype_inet_not_multi(&daddr)) invarg("invalid remote address", *argv); } else if (!matches(*argv, "local")) { - __u32 saddr = 0; - struct in6_addr saddr6 = IN6ADDR_ANY_INIT; - NEXT_ARG(); check_duparg(&attrs, IFLA_VXLAN_LOCAL, "local", *argv); - if (strcmp(*argv, "any")) { - if (!inet_get_addr(*argv, &saddr, &saddr6)) { - fprintf(stderr, "Invalid address \"%s\"\n", *argv); - return -1; - } - } - - if (IN_MULTICAST(ntohl(saddr)) || IN6_IS_ADDR_MULTICAST(&saddr6)) + get_addr(&saddr, *argv, daddr.family); + if (!is_addrtype_inet_not_multi(&saddr)) invarg("invalid local address", *argv); - - if (saddr) - addattr_l(n, 1024, IFLA_VXLAN_LOCAL, &saddr, 4); - else if (!IN6_IS_ADDR_UNSPECIFIED(&saddr6)) - addattr_l(n, 1024, IFLA_VXLAN_LOCAL6, &saddr6, - sizeof(struct in6_addr)); } else if (!matches(*argv, "dev")) { unsigned int link; @@ -350,7 +330,7 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv, return -1; } - if ((gaddr || !IN6_IS_ADDR_UNSPECIFIED(&gaddr6)) && + if (is_addrtype_inet_multi(&daddr) && !VXLAN_ATTRSET(attrs, IFLA_VXLAN_LINK)) { fprintf(stderr, "vxlan: 'group' requires 'dev' to be specified\n"); return -1; @@ -369,18 +349,18 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv, if (VXLAN_ATTRSET(attrs, IFLA_VXLAN_ID)) addattr32(n, 1024, IFLA_VXLAN_ID, vni); - if (gaddr) - addattr_l(n, 1024, IFLA_VXLAN_GROUP, &gaddr, 4); - else if (daddr) - addattr_l(n, 1024, IFLA_VXLAN_GROUP, &daddr, 4); - else if (!IN6_IS_ADDR_UNSPECIFIED(&gaddr6)) - addattr_l(n, 1024, IFLA_VXLAN_GROUP6, &gaddr6, sizeof(struct in6_addr)); - else if (!IN6_IS_ADDR_UNSPECIFIED(&daddr6)) - addattr_l(n, 1024, IFLA_VXLAN_GROUP6, &daddr6, sizeof(struct in6_addr)); - else if (preferred_family == AF_INET) - addattr_l(n, 1024, IFLA_VXLAN_GROUP, &daddr, 4); - else if (preferred_family == AF_INET6) - addattr_l(n, 1024, IFLA_VXLAN_GROUP6, &daddr6, sizeof(struct in6_addr)); + + if (is_addrtype_inet(&saddr)) { + int type = (saddr.family == AF_INET) ? IFLA_VXLAN_LOCAL + : IFLA_VXLAN_LOCAL6; + addattr_l(n, 1024, type, saddr.data, saddr.bytelen); + } + + if (is_addrtype_inet(&daddr)) { + int type = (daddr.family == AF_INET) ? IFLA_VXLAN_GROUP + : IFLA_VXLAN_GROUP6; + addattr_l(n, 1024, type, daddr.data, daddr.bytelen); + } if (!set_op || VXLAN_ATTRSET(attrs, IFLA_VXLAN_LEARNING)) addattr8(n, 1024, IFLA_VXLAN_LEARNING, learning); diff --git a/ip/iproute_lwtunnel.c b/ip/iproute_lwtunnel.c index a1d36ba2..7542addb 100644 --- a/ip/iproute_lwtunnel.c +++ b/ip/iproute_lwtunnel.c @@ -431,7 +431,10 @@ static struct ipv6_sr_hdr *parse_srh(char *segbuf, int hmac, bool encap) i = srh->first_segment; for (s = strtok(segbuf, ","); s; s = strtok(NULL, ",")) { - inet_get_addr(s, NULL, &srh->segments[i]); + inet_prefix addr; + + get_addr(&addr, s, AF_INET6); + memcpy(&srh->segments[i], addr.data, sizeof(struct in6_addr)); i--; } diff --git a/ip/ipseg6.c b/ip/ipseg6.c index 461a3c1c..e3ab31a5 100644 --- a/ip/ipseg6.c +++ b/ip/ipseg6.c @@ -49,7 +49,7 @@ static int genl_family = -1; static struct { unsigned int cmd; - struct in6_addr addr; + inet_prefix addr; __u32 keyid; const char *pass; __u8 alg_id; @@ -152,7 +152,7 @@ static int seg6_do_cmd(void) break; } case SEG6_CMD_SET_TUNSRC: - addattr_l(&req.n, sizeof(req), SEG6_ATTR_DST, &opts.addr, + addattr_l(&req.n, sizeof(req), SEG6_ATTR_DST, opts.addr.data, sizeof(struct in6_addr)); break; case SEG6_CMD_DUMPHMAC: @@ -226,9 +226,7 @@ int do_seg6(int argc, char **argv) } else if (matches(*argv, "set") == 0) { NEXT_ARG(); opts.cmd = SEG6_CMD_SET_TUNSRC; - if (!inet_get_addr(*argv, NULL, &opts.addr)) - invarg("tunsrc ADDRESS value is invalid", - *argv); + get_addr(&opts.addr, *argv, AF_INET6); } else { invarg("unknown", *argv); } diff --git a/lib/utils.c b/lib/utils.c index 9fa52204..e20b60e4 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -534,7 +534,7 @@ int get_addr64(__u64 *ap, const char *cp) return 1; } -int get_addr_1(inet_prefix *addr, const char *name, int family) +static int __get_addr_1(inet_prefix *addr, const char *name, int family) { memset(addr, 0, sizeof(*addr)); @@ -543,9 +543,9 @@ int get_addr_1(inet_prefix *addr, const char *name, int family) strcmp(name, "any") == 0) { if ((family == AF_DECnet) || (family == AF_MPLS)) return -1; - addr->family = family; - addr->bytelen = (family == AF_INET6 ? 16 : 4); - addr->bitlen = -1; + addr->family = (family != AF_UNSPEC) ? family : AF_INET; + addr->bytelen = af_byte_len(addr->family); + addr->bitlen = -2; return 0; } @@ -619,6 +619,36 @@ int get_addr_1(inet_prefix *addr, const char *name, int family) return 0; } +int get_addr_1(inet_prefix *addr, const char *name, int family) +{ + int ret; + + ret = __get_addr_1(addr, name, family); + if (ret) + return ret; + + switch (addr->family) { + case AF_INET: + if (!addr->data[0]) + addr->flags |= ADDRTYPE_INET_UNSPEC; + else if (IN_MULTICAST(ntohl(addr->data[0]))) + addr->flags |= ADDRTYPE_INET_MULTI; + else + addr->flags |= ADDRTYPE_INET; + break; + case AF_INET6: + if (IN6_IS_ADDR_UNSPECIFIED(addr->data)) + addr->flags |= ADDRTYPE_INET_UNSPEC; + else if (IN6_IS_ADDR_MULTICAST(addr->data)) + addr->flags |= ADDRTYPE_INET_MULTI; + else + addr->flags |= ADDRTYPE_INET; + break; + } + + return 0; +} + int af_bit_len(int af) { switch (af) { @@ -644,46 +674,46 @@ int af_byte_len(int af) int get_prefix_1(inet_prefix *dst, char *arg, int family) { - int err; - unsigned int plen; char *slash; - - memset(dst, 0, sizeof(*dst)); - - if (strcmp(arg, "default") == 0 || - strcmp(arg, "any") == 0 || - strcmp(arg, "all") == 0) { - if ((family == AF_DECnet) || (family == AF_MPLS)) - return -1; - dst->family = family; - dst->bytelen = 0; - dst->bitlen = 0; - dst->flags |= PREFIXLEN_SPECIFIED; - return 0; - } + int err, bitlen, flags; slash = strchr(arg, '/'); if (slash) *slash = 0; err = get_addr_1(dst, arg, family); - if (err == 0) { - dst->bitlen = af_bit_len(dst->family); - if (slash) { - if (get_netmask(&plen, slash+1, 0) - || plen > dst->bitlen) { - err = -1; - goto done; - } - dst->flags |= PREFIXLEN_SPECIFIED; - dst->bitlen = plen; - } - } -done: if (slash) *slash = '/'; - return err; + + if (err) + return err; + + bitlen = af_bit_len(dst->family); + + flags = PREFIXLEN_SPECIFIED; + if (slash) { + unsigned int plen; + + if (dst->bitlen == -2) + return -1; + if (get_netmask(&plen, slash + 1, 0)) + return -1; + if (plen > bitlen) + return -1; + + bitlen = plen; + } else { + if (dst->bitlen == -2) + bitlen = 0; + else + flags = 0; + } + + dst->flags |= flags; + dst->bitlen = bitlen; + + return 0; } static const char *family_name_verbose(int family) @@ -1250,14 +1280,6 @@ int makeargs(char *line, char *argv[], int maxargs) return argc; } -int inet_get_addr(const char *src, __u32 *dst, struct in6_addr *dst6) -{ - if (strchr(src, ':')) - return inet_pton(AF_INET6, src, dst6); - else - return inet_pton(AF_INET, src, dst); -} - void print_nlmsg_timestamp(FILE *fp, const struct nlmsghdr *n) { char *tstr;