X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=lib%2Fpackets.c;h=990c407c51f9ed6cd54ff8ec65c9138f2a1e2c36;hb=2e4450aa35c6e7a9c97c930f5d43028cfbfbe07f;hp=1bf887e2269e1f0919fabb004595b6c073db50e8;hpb=ee89ea7b477bb4fd05137de03b2e8443807ed9f4;p=mirror_ovs.git diff --git a/lib/packets.c b/lib/packets.c index 1bf887e22..990c407c5 100644 --- a/lib/packets.c +++ b/lib/packets.c @@ -140,10 +140,15 @@ eth_addr_is_reserved(const struct eth_addr ea) return false; } +/* Attempts to parse 's' as an Ethernet address. If successful, stores the + * address in 'ea' and returns true, otherwise zeros 'ea' and returns + * false. This function checks trailing characters. */ bool eth_addr_from_string(const char *s, struct eth_addr *ea) { - if (ovs_scan(s, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(*ea))) { + int n = 0; + if (ovs_scan(s, ETH_ADDR_SCAN_FMT"%n", ETH_ADDR_SCAN_ARGS(*ea), &n) + && !s[n]) { return true; } else { *ea = eth_addr_zero; @@ -424,6 +429,24 @@ ip_parse(const char *s, ovs_be32 *ip) return inet_pton(AF_INET, s, ip) == 1; } +/* Parses string 's', which must be an IP address with a port number + * with ":" as a separator (e.g.: 192.168.1.2:80). + * Stores the IP address into '*ip' and port number to '*port'. */ +char * OVS_WARN_UNUSED_RESULT +ip_parse_port(const char *s, ovs_be32 *ip, ovs_be16 *port) +{ + int n = 0; + if (!ovs_scan_len(s, &n, IP_PORT_SCAN_FMT, + IP_PORT_SCAN_ARGS(ip, port))) { + return xasprintf("%s: invalid IP address or port number", s); + } + + if (s[n]) { + return xasprintf("%s: invalid IP address or port number", s); + } + return NULL; +} + /* Parses string 's', which must be an IP address with an optional netmask or * CIDR prefix length. Stores the IP address into '*ip', netmask into '*mask', * (255.255.255.255, if 's' lacks a netmask), and number of scanned characters @@ -1319,29 +1342,36 @@ compose_arp__(struct dp_packet *b) dp_packet_set_l3(b, arp); } -/* This function expect packet with ethernet header with correct +/* This function expects packet with ethernet header with correct * l3 pointer set. */ static void * -compose_ipv6(struct dp_packet *packet, uint8_t proto, const ovs_be32 src[4], - const ovs_be32 dst[4], uint8_t key_tc, ovs_be32 key_fl, - uint8_t key_hl, int size) +compose_ipv6(struct dp_packet *packet, uint8_t proto, + const struct in6_addr *src, const struct in6_addr *dst, + uint8_t key_tc, ovs_be32 key_fl, uint8_t key_hl, int size) { struct ip6_hdr *nh; void *data; + /* Copy 'src' and 'dst' to temporary buffers to prevent misaligned + * accesses. */ + ovs_be32 sbuf[4], dbuf[4]; + memcpy(sbuf, src, sizeof sbuf); + memcpy(dbuf, dst, sizeof dbuf); + nh = dp_packet_l3(packet); nh->ip6_vfc = 0x60; nh->ip6_nxt = proto; nh->ip6_plen = htons(size); data = dp_packet_put_zeros(packet, size); dp_packet_set_l4(packet, data); - packet_set_ipv6(packet, src, dst, key_tc, key_fl, key_hl); + packet_set_ipv6(packet, sbuf, dbuf, key_tc, key_fl, key_hl); return data; } +/* Compose an IPv6 Neighbor Discovery Neighbor Solicitation message. */ void -compose_nd(struct dp_packet *b, const struct eth_addr eth_src, - struct in6_addr *ipv6_src, struct in6_addr *ipv6_dst) +compose_nd_ns(struct dp_packet *b, const struct eth_addr eth_src, + const struct in6_addr *ipv6_src, const struct in6_addr *ipv6_dst) { struct in6_addr sn_addr; struct eth_addr eth_dst; @@ -1353,11 +1383,8 @@ compose_nd(struct dp_packet *b, const struct eth_addr eth_src, ipv6_multicast_to_ethernet(ð_dst, &sn_addr); eth_compose(b, eth_dst, eth_src, ETH_TYPE_IPV6, IPV6_HEADER_LEN); - ns = compose_ipv6(b, IPPROTO_ICMPV6, - ALIGNED_CAST(ovs_be32 *, ipv6_src->s6_addr), - ALIGNED_CAST(ovs_be32 *, sn_addr.s6_addr), - 0, 0, 255, - ND_MSG_LEN + ND_OPT_LEN); + ns = compose_ipv6(b, IPPROTO_ICMPV6, ipv6_src, &sn_addr, + 0, 0, 255, ND_MSG_LEN + ND_OPT_LEN); ns->icmph.icmp6_type = ND_NEIGHBOR_SOLICIT; ns->icmph.icmp6_code = 0; @@ -1367,27 +1394,31 @@ compose_nd(struct dp_packet *b, const struct eth_addr eth_src, nd_opt->nd_opt_type = ND_OPT_SOURCE_LINKADDR; nd_opt->nd_opt_len = 1; - packet_set_nd(b, ALIGNED_CAST(ovs_be32 *, ipv6_dst->s6_addr), - eth_src, eth_addr_zero); + /* Copy target address to temp buffer to prevent misaligned access. */ + ovs_be32 tbuf[4]; + memcpy(tbuf, ipv6_dst->s6_addr, sizeof tbuf); + packet_set_nd(b, tbuf, eth_src, eth_addr_zero); + ns->icmph.icmp6_cksum = 0; icmp_csum = packet_csum_pseudoheader6(dp_packet_l3(b)); ns->icmph.icmp6_cksum = csum_finish(csum_continue(icmp_csum, ns, ND_MSG_LEN + ND_OPT_LEN)); } +/* Compose an IPv6 Neighbor Discovery Neighbor Advertisement message. */ void -compose_na(struct dp_packet *b, - const struct eth_addr eth_src, const struct eth_addr eth_dst, - const ovs_be32 ipv6_src[4], const ovs_be32 ipv6_dst[4], - ovs_be32 rso_flags) +compose_nd_na(struct dp_packet *b, + const struct eth_addr eth_src, const struct eth_addr eth_dst, + const struct in6_addr *ipv6_src, const struct in6_addr *ipv6_dst, + ovs_be32 rso_flags) { struct ovs_nd_msg *na; struct ovs_nd_opt *nd_opt; uint32_t icmp_csum; eth_compose(b, eth_dst, eth_src, ETH_TYPE_IPV6, IPV6_HEADER_LEN); - na = compose_ipv6(b, IPPROTO_ICMPV6, ipv6_src, ipv6_dst, 0, 0, 255, - ND_MSG_LEN + ND_OPT_LEN); + na = compose_ipv6(b, IPPROTO_ICMPV6, ipv6_src, ipv6_dst, + 0, 0, 255, ND_MSG_LEN + ND_OPT_LEN); na->icmph.icmp6_type = ND_NEIGHBOR_ADVERT; na->icmph.icmp6_code = 0; @@ -1397,7 +1428,11 @@ compose_na(struct dp_packet *b, nd_opt->nd_opt_type = ND_OPT_TARGET_LINKADDR; nd_opt->nd_opt_len = 1; - packet_set_nd(b, ipv6_src, eth_addr_zero, eth_src); + /* Copy target address to temp buffer to prevent misaligned access. */ + ovs_be32 tbuf[4]; + memcpy(tbuf, ipv6_src->s6_addr, sizeof tbuf); + packet_set_nd(b, tbuf, eth_addr_zero, eth_src); + na->icmph.icmp6_cksum = 0; icmp_csum = packet_csum_pseudoheader6(dp_packet_l3(b)); na->icmph.icmp6_cksum = csum_finish(csum_continue(icmp_csum, na,