diff --git a/include/utils.h b/include/utils.h index 4dc514d6..867e5404 100644 --- a/include/utils.h +++ b/include/utils.h @@ -65,6 +65,11 @@ enum { ADDRTYPE_INET_MULTI = ADDRTYPE_INET | ADDRTYPE_MULTI }; +static inline void inet_prefix_reset(inet_prefix *p) +{ + p->flags = 0; +} + static inline bool is_addrtype_inet(const inet_prefix *p) { return p->flags & ADDRTYPE_INET; diff --git a/ip/iplink_geneve.c b/ip/iplink_geneve.c index c6660726..1fcdd83a 100644 --- a/ip/iplink_geneve.c +++ b/ip/iplink_geneve.c @@ -71,7 +71,7 @@ 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; + inet_prefix_reset(&daddr); while (argc > 0) { if (!matches(*argv, "id") || diff --git a/ip/iplink_vxlan.c b/ip/iplink_vxlan.c index 00875ba7..d768c07e 100644 --- a/ip/iplink_vxlan.c +++ b/ip/iplink_vxlan.c @@ -74,8 +74,7 @@ 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; + inet_prefix saddr, daddr; __u32 vni = 0; __u8 learning = 1; __u16 dstport = 0; @@ -85,7 +84,9 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv, !(n->nlmsg_flags & NLM_F_CREATE)); saddr.family = daddr.family = AF_UNSPEC; - saddr.flags = daddr.flags = 0; + + inet_prefix_reset(&saddr); + inet_prefix_reset(&daddr); while (argc > 0) { if (!matches(*argv, "id") || diff --git a/ip/link_gre.c b/ip/link_gre.c index e3e53239..64588d75 100644 --- a/ip/link_gre.c +++ b/ip/link_gre.c @@ -86,8 +86,7 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv, __u16 oflags = 0; __be32 ikey = 0; __be32 okey = 0; - unsigned int saddr = 0; - unsigned int daddr = 0; + inet_prefix saddr, daddr; __u8 pmtudisc = 1; __u8 ignore_df = 0; __u8 tos = 0; @@ -104,7 +103,12 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv, __u8 erspan_dir = 0; __u16 erspan_hwid = 0; + inet_prefix_reset(&saddr); + inet_prefix_reset(&daddr); + if (!(n->nlmsg_flags & NLM_F_CREATE)) { + const struct rtattr *rta; + if (rtnl_talk(&rth, &req.n, &answer) < 0) { get_failed: fprintf(stderr, @@ -130,6 +134,14 @@ get_failed: parse_rtattr_nested(greinfo, IFLA_GRE_MAX, linkinfo[IFLA_INFO_DATA]); + rta = greinfo[IFLA_GRE_LOCAL]; + if (rta && get_addr_rta(&saddr, rta, AF_INET)) + goto get_failed; + + rta = greinfo[IFLA_GRE_REMOTE]; + if (rta && get_addr_rta(&daddr, rta, AF_INET)) + goto get_failed; + if (greinfo[IFLA_GRE_IKEY]) ikey = rta_getattr_u32(greinfo[IFLA_GRE_IKEY]); @@ -142,12 +154,6 @@ get_failed: if (greinfo[IFLA_GRE_OFLAGS]) oflags = rta_getattr_u16(greinfo[IFLA_GRE_OFLAGS]); - if (greinfo[IFLA_GRE_LOCAL]) - saddr = rta_getattr_u32(greinfo[IFLA_GRE_LOCAL]); - - if (greinfo[IFLA_GRE_REMOTE]) - daddr = rta_getattr_u32(greinfo[IFLA_GRE_REMOTE]); - if (greinfo[IFLA_GRE_PMTUDISC]) pmtudisc = rta_getattr_u8( greinfo[IFLA_GRE_PMTUDISC]); @@ -232,10 +238,10 @@ get_failed: pmtudisc = 1; } else if (!matches(*argv, "remote")) { NEXT_ARG(); - daddr = get_addr32(*argv); + get_addr(&daddr, *argv, AF_INET); } else if (!matches(*argv, "local")) { NEXT_ARG(); - saddr = get_addr32(*argv); + get_addr(&saddr, *argv, AF_INET); } else if (!matches(*argv, "dev")) { NEXT_ARG(); link = ll_name_to_index(*argv); @@ -343,17 +349,20 @@ get_failed: argc--; argv++; } - if (!ikey && IN_MULTICAST(ntohl(daddr))) { - ikey = daddr; - iflags |= GRE_KEY; - } - if (!okey && IN_MULTICAST(ntohl(daddr))) { - okey = daddr; - oflags |= GRE_KEY; - } - if (IN_MULTICAST(ntohl(daddr)) && !saddr) { - fprintf(stderr, "A broadcast tunnel requires a source address.\n"); - return -1; + if (is_addrtype_inet_multi(&daddr)) { + if (!ikey) { + ikey = daddr.data[0]; + iflags |= GRE_KEY; + } + if (!okey) { + okey = daddr.data[0]; + oflags |= GRE_KEY; + } + if (!is_addrtype_inet_not_unspec(&saddr)) { + fprintf(stderr, + "A broadcast tunnel requires a source address.\n"); + return -1; + } } if (metadata) { @@ -365,8 +374,10 @@ get_failed: addattr32(n, 1024, IFLA_GRE_OKEY, okey); addattr_l(n, 1024, IFLA_GRE_IFLAGS, &iflags, 2); addattr_l(n, 1024, IFLA_GRE_OFLAGS, &oflags, 2); - addattr_l(n, 1024, IFLA_GRE_LOCAL, &saddr, 4); - addattr_l(n, 1024, IFLA_GRE_REMOTE, &daddr, 4); + if (is_addrtype_inet(&saddr)) + addattr_l(n, 1024, IFLA_GRE_LOCAL, saddr.data, saddr.bytelen); + if (is_addrtype_inet(&daddr)) + addattr_l(n, 1024, IFLA_GRE_REMOTE, daddr.data, daddr.bytelen); addattr_l(n, 1024, IFLA_GRE_PMTUDISC, &pmtudisc, 1); if (ignore_df) addattr8(n, 1024, IFLA_GRE_IGNORE_DF, ignore_df & 1); diff --git a/ip/link_gre6.c b/ip/link_gre6.c index 251ae0e3..6c77038a 100644 --- a/ip/link_gre6.c +++ b/ip/link_gre6.c @@ -97,8 +97,7 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv, __u16 oflags = 0; __be32 ikey = 0; __be32 okey = 0; - struct in6_addr raddr = IN6ADDR_ANY_INIT; - struct in6_addr laddr = IN6ADDR_ANY_INIT; + inet_prefix saddr, daddr; __u8 hop_limit = DEFAULT_TNL_HOP_LIMIT; __u8 encap_limit = IPV6_DEFAULT_TNL_ENCAP_LIMIT; __u32 flowinfo = 0; @@ -115,7 +114,12 @@ static int gre_parse_opt(struct link_util *lu, int argc, char **argv, __u8 erspan_dir = 0; __u16 erspan_hwid = 0; + inet_prefix_reset(&saddr); + inet_prefix_reset(&daddr); + if (!(n->nlmsg_flags & NLM_F_CREATE)) { + const struct rtattr *rta; + if (rtnl_talk(&rth, &req.n, &answer) < 0) { get_failed: fprintf(stderr, @@ -141,6 +145,14 @@ get_failed: parse_rtattr_nested(greinfo, IFLA_GRE_MAX, linkinfo[IFLA_INFO_DATA]); + rta = greinfo[IFLA_GRE_LOCAL]; + if (rta && get_addr_rta(&saddr, rta, AF_INET6)) + goto get_failed; + + rta = greinfo[IFLA_GRE_REMOTE]; + if (rta && get_addr_rta(&daddr, rta, AF_INET6)) + goto get_failed; + if (greinfo[IFLA_GRE_IKEY]) ikey = rta_getattr_u32(greinfo[IFLA_GRE_IKEY]); @@ -153,12 +165,6 @@ get_failed: if (greinfo[IFLA_GRE_OFLAGS]) oflags = rta_getattr_u16(greinfo[IFLA_GRE_OFLAGS]); - if (greinfo[IFLA_GRE_LOCAL]) - memcpy(&laddr, RTA_DATA(greinfo[IFLA_GRE_LOCAL]), sizeof(laddr)); - - if (greinfo[IFLA_GRE_REMOTE]) - memcpy(&raddr, RTA_DATA(greinfo[IFLA_GRE_REMOTE]), sizeof(raddr)); - if (greinfo[IFLA_GRE_TTL]) hop_limit = rta_getattr_u8(greinfo[IFLA_GRE_TTL]); @@ -236,17 +242,11 @@ get_failed: } else if (!matches(*argv, "ocsum")) { oflags |= GRE_CSUM; } else if (!matches(*argv, "remote")) { - inet_prefix addr; - NEXT_ARG(); - get_addr(&addr, *argv, AF_INET6); - memcpy(&raddr, &addr.data, sizeof(raddr)); + get_addr(&daddr, *argv, AF_INET6); } else if (!matches(*argv, "local")) { - inet_prefix addr; - NEXT_ARG(); - get_addr(&addr, *argv, AF_INET6); - memcpy(&laddr, &addr.data, sizeof(laddr)); + get_addr(&saddr, *argv, AF_INET6); } else if (!matches(*argv, "dev")) { NEXT_ARG(); link = ll_name_to_index(*argv); @@ -398,8 +398,10 @@ get_failed: addattr32(n, 1024, IFLA_GRE_OKEY, okey); addattr_l(n, 1024, IFLA_GRE_IFLAGS, &iflags, 2); addattr_l(n, 1024, IFLA_GRE_OFLAGS, &oflags, 2); - addattr_l(n, 1024, IFLA_GRE_LOCAL, &laddr, sizeof(laddr)); - addattr_l(n, 1024, IFLA_GRE_REMOTE, &raddr, sizeof(raddr)); + if (is_addrtype_inet(&saddr)) + addattr_l(n, 1024, IFLA_GRE_LOCAL, saddr.data, saddr.bytelen); + if (is_addrtype_inet(&daddr)) + addattr_l(n, 1024, IFLA_GRE_REMOTE, daddr.data, daddr.bytelen); if (link) addattr32(n, 1024, IFLA_GRE_LINK, link); addattr_l(n, 1024, IFLA_GRE_TTL, &hop_limit, 1); diff --git a/ip/link_ip6tnl.c b/ip/link_ip6tnl.c index 8a45d42b..77a90900 100644 --- a/ip/link_ip6tnl.c +++ b/ip/link_ip6tnl.c @@ -93,8 +93,7 @@ static int ip6tunnel_parse_opt(struct link_util *lu, int argc, char **argv, struct rtattr *linkinfo[IFLA_INFO_MAX+1]; struct rtattr *iptuninfo[IFLA_IPTUN_MAX + 1]; int len; - struct in6_addr laddr = IN6ADDR_ANY_INIT; - struct in6_addr raddr = IN6ADDR_ANY_INIT; + inet_prefix saddr, daddr; __u8 hop_limit = DEFAULT_TNL_HOP_LIMIT; __u8 encap_limit = IPV6_DEFAULT_TNL_ENCAP_LIMIT; __u32 flowinfo = 0; @@ -108,7 +107,12 @@ static int ip6tunnel_parse_opt(struct link_util *lu, int argc, char **argv, __u8 metadata = 0; __u32 fwmark = 0; + inet_prefix_reset(&saddr); + inet_prefix_reset(&daddr); + if (!(n->nlmsg_flags & NLM_F_CREATE)) { + const struct rtattr *rta; + if (rtnl_talk(&rth, &req.n, &answer) < 0) { get_failed: fprintf(stderr, @@ -134,13 +138,13 @@ get_failed: parse_rtattr_nested(iptuninfo, IFLA_IPTUN_MAX, linkinfo[IFLA_INFO_DATA]); - if (iptuninfo[IFLA_IPTUN_LOCAL]) - memcpy(&laddr, RTA_DATA(iptuninfo[IFLA_IPTUN_LOCAL]), - sizeof(laddr)); + rta = iptuninfo[IFLA_IPTUN_LOCAL]; + if (rta && get_addr_rta(&saddr, rta, AF_INET6)) + goto get_failed; - if (iptuninfo[IFLA_IPTUN_REMOTE]) - memcpy(&raddr, RTA_DATA(iptuninfo[IFLA_IPTUN_REMOTE]), - sizeof(raddr)); + rta = iptuninfo[IFLA_IPTUN_REMOTE]; + if (rta && get_addr_rta(&daddr, rta, AF_INET6)) + goto get_failed; if (iptuninfo[IFLA_IPTUN_TTL]) hop_limit = rta_getattr_u8(iptuninfo[IFLA_IPTUN_TTL]); @@ -185,17 +189,11 @@ get_failed: else invarg("Cannot guess tunnel mode.", *argv); } else if (strcmp(*argv, "remote") == 0) { - inet_prefix addr; - NEXT_ARG(); - get_addr(&addr, *argv, AF_INET6); - memcpy(&raddr, addr.data, sizeof(raddr)); + get_addr(&daddr, *argv, AF_INET6); } else if (strcmp(*argv, "local") == 0) { - inet_prefix addr; - NEXT_ARG(); - get_addr(&addr, *argv, AF_INET6); - memcpy(&laddr, addr.data, sizeof(laddr)); + get_addr(&saddr, *argv, AF_INET6); } else if (matches(*argv, "dev") == 0) { NEXT_ARG(); link = ll_name_to_index(*argv); @@ -322,8 +320,14 @@ get_failed: return 0; } - addattr_l(n, 1024, IFLA_IPTUN_LOCAL, &laddr, sizeof(laddr)); - addattr_l(n, 1024, IFLA_IPTUN_REMOTE, &raddr, sizeof(raddr)); + if (is_addrtype_inet(&saddr)) { + addattr_l(n, 1024, IFLA_IPTUN_LOCAL, + saddr.data, saddr.bytelen); + } + if (is_addrtype_inet(&daddr)) { + addattr_l(n, 1024, IFLA_IPTUN_REMOTE, + daddr.data, daddr.bytelen); + } addattr8(n, 1024, IFLA_IPTUN_TTL, hop_limit); addattr8(n, 1024, IFLA_IPTUN_ENCAP_LIMIT, encap_limit); addattr32(n, 1024, IFLA_IPTUN_FLOWINFO, flowinfo); diff --git a/ip/link_iptnl.c b/ip/link_iptnl.c index bc1074e9..acd9f45b 100644 --- a/ip/link_iptnl.c +++ b/ip/link_iptnl.c @@ -90,16 +90,11 @@ static int iptunnel_parse_opt(struct link_util *lu, int argc, char **argv, struct rtattr *linkinfo[IFLA_INFO_MAX+1]; struct rtattr *iptuninfo[IFLA_IPTUN_MAX + 1]; int len; - __u32 laddr = 0; - __u32 raddr = 0; + inet_prefix saddr, daddr, ip6rdprefix, ip6rdrelayprefix; __u8 pmtudisc = 1; __u8 tos = 0; __u16 iflags = 0; __u8 ttl = 0; - struct in6_addr ip6rdprefix = {}; - __u16 ip6rdprefixlen = 0; - __u32 ip6rdrelayprefix = 0; - __u16 ip6rdrelayprefixlen = 0; __u8 proto = 0; __u32 link = 0; __u16 encaptype = 0; @@ -109,7 +104,15 @@ static int iptunnel_parse_opt(struct link_util *lu, int argc, char **argv, __u8 metadata = 0; __u32 fwmark = 0; + inet_prefix_reset(&saddr); + inet_prefix_reset(&daddr); + + inet_prefix_reset(&ip6rdprefix); + inet_prefix_reset(&ip6rdrelayprefix); + if (!(n->nlmsg_flags & NLM_F_CREATE)) { + const struct rtattr *rta; + if (rtnl_talk(&rth, &req.n, &answer) < 0) { get_failed: fprintf(stderr, @@ -135,11 +138,27 @@ get_failed: parse_rtattr_nested(iptuninfo, IFLA_IPTUN_MAX, linkinfo[IFLA_INFO_DATA]); - if (iptuninfo[IFLA_IPTUN_LOCAL]) - laddr = rta_getattr_u32(iptuninfo[IFLA_IPTUN_LOCAL]); + rta = iptuninfo[IFLA_IPTUN_LOCAL]; + if (rta && get_addr_rta(&saddr, rta, AF_INET)) + goto get_failed; - if (iptuninfo[IFLA_IPTUN_REMOTE]) - raddr = rta_getattr_u32(iptuninfo[IFLA_IPTUN_REMOTE]); + rta = iptuninfo[IFLA_IPTUN_REMOTE]; + if (rta && get_addr_rta(&daddr, rta, AF_INET)) + goto get_failed; + + rta = iptuninfo[IFLA_IPTUN_6RD_PREFIX]; + if (rta && get_addr_rta(&ip6rdprefix, rta, AF_INET6)) + goto get_failed; + + rta = iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIX]; + if (rta && get_addr_rta(&ip6rdrelayprefix, rta, AF_INET)) + goto get_failed; + + rta = iptuninfo[IFLA_IPTUN_6RD_PREFIXLEN]; + ip6rdprefix.bitlen = rta ? rta_getattr_u16(rta) : 0; + + rta = iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]; + ip6rdrelayprefix.bitlen = rta ? rta_getattr_u16(rta) : 0; if (iptuninfo[IFLA_IPTUN_TTL]) ttl = rta_getattr_u8(iptuninfo[IFLA_IPTUN_TTL]); @@ -168,22 +187,7 @@ get_failed: encapsport = rta_getattr_u16(iptuninfo[IFLA_IPTUN_ENCAP_SPORT]); if (iptuninfo[IFLA_IPTUN_ENCAP_DPORT]) encapdport = rta_getattr_u16(iptuninfo[IFLA_IPTUN_ENCAP_DPORT]); - if (iptuninfo[IFLA_IPTUN_6RD_PREFIX]) - memcpy(&ip6rdprefix, - RTA_DATA(iptuninfo[IFLA_IPTUN_6RD_PREFIX]), - sizeof(laddr)); - if (iptuninfo[IFLA_IPTUN_6RD_PREFIXLEN]) - ip6rdprefixlen = - rta_getattr_u16(iptuninfo[IFLA_IPTUN_6RD_PREFIXLEN]); - - if (iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIX]) - ip6rdrelayprefix = - rta_getattr_u32(iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIX]); - - if (iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]) - ip6rdrelayprefixlen = - rta_getattr_u16(iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]); if (iptuninfo[IFLA_IPTUN_COLLECT_METADATA]) metadata = 1; @@ -214,10 +218,10 @@ get_failed: invarg("Cannot guess tunnel mode.", *argv); } else if (strcmp(*argv, "remote") == 0) { NEXT_ARG(); - raddr = get_addr32(*argv); + get_addr(&daddr, *argv, AF_INET); } else if (strcmp(*argv, "local") == 0) { NEXT_ARG(); - laddr = get_addr32(*argv); + get_addr(&saddr, *argv, AF_INET); } else if (matches(*argv, "dev") == 0) { NEXT_ARG(); link = ll_name_to_index(*argv); @@ -289,29 +293,16 @@ get_failed: } else if (strcmp(*argv, "external") == 0) { metadata = 1; } else if (strcmp(*argv, "6rd-prefix") == 0) { - inet_prefix prefix; - NEXT_ARG(); - if (get_prefix(&prefix, *argv, AF_INET6)) + if (get_prefix(&ip6rdprefix, *argv, AF_INET6)) invarg("invalid 6rd_prefix\n", *argv); - memcpy(&ip6rdprefix, prefix.data, 16); - ip6rdprefixlen = prefix.bitlen; } else if (strcmp(*argv, "6rd-relay_prefix") == 0) { - inet_prefix prefix; - NEXT_ARG(); - if (get_prefix(&prefix, *argv, AF_INET)) + if (get_prefix(&ip6rdrelayprefix, *argv, AF_INET)) invarg("invalid 6rd-relay_prefix\n", *argv); - memcpy(&ip6rdrelayprefix, prefix.data, 4); - ip6rdrelayprefixlen = prefix.bitlen; } else if (strcmp(*argv, "6rd-reset") == 0) { - inet_prefix prefix; - - get_prefix(&prefix, "2002::", AF_INET6); - memcpy(&ip6rdprefix, prefix.data, 16); - ip6rdprefixlen = 16; - ip6rdrelayprefix = 0; - ip6rdrelayprefixlen = 0; + get_prefix(&ip6rdprefix, "2002::/16", AF_INET6); + inet_prefix_reset(&ip6rdrelayprefix); } else if (strcmp(*argv, "fwmark") == 0) { NEXT_ARG(); if (get_u32(&fwmark, *argv, 0)) @@ -334,8 +325,14 @@ get_failed: return 0; } - addattr32(n, 1024, IFLA_IPTUN_LOCAL, laddr); - addattr32(n, 1024, IFLA_IPTUN_REMOTE, raddr); + if (is_addrtype_inet(&saddr)) { + addattr_l(n, 1024, IFLA_IPTUN_LOCAL, + saddr.data, saddr.bytelen); + } + if (is_addrtype_inet(&daddr)) { + addattr_l(n, 1024, IFLA_IPTUN_REMOTE, + daddr.data, daddr.bytelen); + } addattr8(n, 1024, IFLA_IPTUN_PMTUDISC, pmtudisc); addattr8(n, 1024, IFLA_IPTUN_TOS, tos); addattr8(n, 1024, IFLA_IPTUN_TTL, ttl); @@ -349,15 +346,17 @@ get_failed: if (strcmp(lu->id, "sit") == 0) { addattr16(n, 1024, IFLA_IPTUN_FLAGS, iflags); - if (ip6rdprefixlen) { + if (is_addrtype_inet(&ip6rdprefix)) { addattr_l(n, 1024, IFLA_IPTUN_6RD_PREFIX, - &ip6rdprefix, sizeof(ip6rdprefix)); + ip6rdprefix.data, ip6rdprefix.bytelen); addattr16(n, 1024, IFLA_IPTUN_6RD_PREFIXLEN, - ip6rdprefixlen); + ip6rdprefix.bitlen); + } + if (is_addrtype_inet(&ip6rdrelayprefix)) { addattr32(n, 1024, IFLA_IPTUN_6RD_RELAY_PREFIX, - ip6rdrelayprefix); + ip6rdrelayprefix.data[0]); addattr16(n, 1024, IFLA_IPTUN_6RD_RELAY_PREFIXLEN, - ip6rdrelayprefixlen); + ip6rdrelayprefix.bitlen); } } diff --git a/ip/link_vti.c b/ip/link_vti.c index edd17fe2..99e10e8a 100644 --- a/ip/link_vti.c +++ b/ip/link_vti.c @@ -64,13 +64,17 @@ static int vti_parse_opt(struct link_util *lu, int argc, char **argv, struct rtattr *vtiinfo[IFLA_VTI_MAX + 1]; __be32 ikey = 0; __be32 okey = 0; - unsigned int saddr = 0; - unsigned int daddr = 0; + inet_prefix saddr, daddr; unsigned int link = 0; __u32 fwmark = 0; int len; + inet_prefix_reset(&saddr); + inet_prefix_reset(&daddr); + if (!(n->nlmsg_flags & NLM_F_CREATE)) { + const struct rtattr *rta; + if (rtnl_talk(&rth, &req.n, &answer) < 0) { get_failed: fprintf(stderr, @@ -96,18 +100,20 @@ get_failed: parse_rtattr_nested(vtiinfo, IFLA_VTI_MAX, linkinfo[IFLA_INFO_DATA]); + rta = vtiinfo[IFLA_VTI_LOCAL]; + if (rta && get_addr_rta(&saddr, rta, AF_INET)) + goto get_failed; + + rta = vtiinfo[IFLA_VTI_REMOTE]; + if (rta && get_addr_rta(&daddr, rta, AF_INET)) + goto get_failed; + if (vtiinfo[IFLA_VTI_IKEY]) ikey = rta_getattr_u32(vtiinfo[IFLA_VTI_IKEY]); if (vtiinfo[IFLA_VTI_OKEY]) okey = rta_getattr_u32(vtiinfo[IFLA_VTI_OKEY]); - if (vtiinfo[IFLA_VTI_LOCAL]) - saddr = rta_getattr_u32(vtiinfo[IFLA_VTI_LOCAL]); - - if (vtiinfo[IFLA_VTI_REMOTE]) - daddr = rta_getattr_u32(vtiinfo[IFLA_VTI_REMOTE]); - if (vtiinfo[IFLA_VTI_LINK]) link = rta_getattr_u8(vtiinfo[IFLA_VTI_LINK]); @@ -129,10 +135,10 @@ get_failed: okey = tnl_parse_key("okey", *argv); } else if (!matches(*argv, "remote")) { NEXT_ARG(); - daddr = get_addr32(*argv); + get_addr(&daddr, *argv, AF_INET); } else if (!matches(*argv, "local")) { NEXT_ARG(); - saddr = get_addr32(*argv); + get_addr(&saddr, *argv, AF_INET); } else if (!matches(*argv, "dev")) { NEXT_ARG(); link = ll_name_to_index(*argv); @@ -154,8 +160,10 @@ get_failed: addattr32(n, 1024, IFLA_VTI_IKEY, ikey); addattr32(n, 1024, IFLA_VTI_OKEY, okey); - addattr_l(n, 1024, IFLA_VTI_LOCAL, &saddr, 4); - addattr_l(n, 1024, IFLA_VTI_REMOTE, &daddr, 4); + if (is_addrtype_inet(&saddr)) + addattr_l(n, 1024, IFLA_VTI_LOCAL, saddr.data, saddr.bytelen); + if (is_addrtype_inet(&daddr)) + addattr_l(n, 1024, IFLA_VTI_REMOTE, daddr.data, daddr.bytelen); addattr32(n, 1024, IFLA_VTI_FWMARK, fwmark); if (link) addattr32(n, 1024, IFLA_VTI_LINK, link); diff --git a/ip/link_vti6.c b/ip/link_vti6.c index 1276ebd0..1df6579b 100644 --- a/ip/link_vti6.c +++ b/ip/link_vti6.c @@ -64,15 +64,19 @@ static int vti6_parse_opt(struct link_util *lu, int argc, char **argv, struct rtattr *tb[IFLA_MAX + 1]; struct rtattr *linkinfo[IFLA_INFO_MAX+1]; struct rtattr *vtiinfo[IFLA_VTI_MAX + 1]; - struct in6_addr saddr = IN6ADDR_ANY_INIT; - struct in6_addr daddr = IN6ADDR_ANY_INIT; __be32 ikey = 0; __be32 okey = 0; + inet_prefix saddr, daddr; unsigned int link = 0; __u32 fwmark = 0; int len; + inet_prefix_reset(&saddr); + inet_prefix_reset(&daddr); + if (!(n->nlmsg_flags & NLM_F_CREATE)) { + const struct rtattr *rta; + if (rtnl_talk(&rth, &req.n, &answer) < 0) { get_failed: fprintf(stderr, @@ -98,18 +102,20 @@ get_failed: parse_rtattr_nested(vtiinfo, IFLA_VTI_MAX, linkinfo[IFLA_INFO_DATA]); + rta = vtiinfo[IFLA_VTI_LOCAL]; + if (rta && get_addr_rta(&saddr, rta, AF_INET6)) + goto get_failed; + + rta = vtiinfo[IFLA_VTI_REMOTE]; + if (rta && get_addr_rta(&daddr, rta, AF_INET6)) + goto get_failed; + if (vtiinfo[IFLA_VTI_IKEY]) ikey = rta_getattr_u32(vtiinfo[IFLA_VTI_IKEY]); if (vtiinfo[IFLA_VTI_OKEY]) okey = rta_getattr_u32(vtiinfo[IFLA_VTI_OKEY]); - if (vtiinfo[IFLA_VTI_LOCAL]) - memcpy(&saddr, RTA_DATA(vtiinfo[IFLA_VTI_LOCAL]), sizeof(saddr)); - - if (vtiinfo[IFLA_VTI_REMOTE]) - memcpy(&daddr, RTA_DATA(vtiinfo[IFLA_VTI_REMOTE]), sizeof(daddr)); - if (vtiinfo[IFLA_VTI_LINK]) link = rta_getattr_u8(vtiinfo[IFLA_VTI_LINK]); @@ -130,17 +136,11 @@ get_failed: NEXT_ARG(); okey = tnl_parse_key("okey", *argv); } else if (!matches(*argv, "remote")) { - inet_prefix addr; - NEXT_ARG(); - get_addr(&addr, *argv, AF_INET6); - memcpy(&daddr, addr.data, sizeof(daddr)); + get_addr(&daddr, *argv, AF_INET6); } else if (!matches(*argv, "local")) { - inet_prefix addr; - NEXT_ARG(); - get_addr(&addr, *argv, AF_INET6); - memcpy(&saddr, addr.data, sizeof(saddr)); + get_addr(&saddr, *argv, AF_INET6); } else if (!matches(*argv, "dev")) { NEXT_ARG(); link = ll_name_to_index(*argv); @@ -162,8 +162,10 @@ get_failed: addattr32(n, 1024, IFLA_VTI_IKEY, ikey); addattr32(n, 1024, IFLA_VTI_OKEY, okey); - addattr_l(n, 1024, IFLA_VTI_LOCAL, &saddr, sizeof(saddr)); - addattr_l(n, 1024, IFLA_VTI_REMOTE, &daddr, sizeof(daddr)); + if (is_addrtype_inet(&saddr)) + addattr_l(n, 1024, IFLA_VTI_LOCAL, saddr.data, saddr.bytelen); + if (is_addrtype_inet(&daddr)) + addattr_l(n, 1024, IFLA_VTI_REMOTE, daddr.data, daddr.bytelen); addattr32(n, 1024, IFLA_VTI_FWMARK, fwmark); if (link) addattr32(n, 1024, IFLA_VTI_LINK, link);