diff options
author | Mark Michelson <mmichels@redhat.com> | 2018-02-09 09:11:00 -0600 |
---|---|---|
committer | Ben Pfaff <blp@ovn.org> | 2018-02-09 09:59:50 -0800 |
commit | 995933f224d3f682541ef060a949986620df5f05 (patch) | |
tree | 321b8cb9c53beedd8c90b97e4ba29f5de33b7bc9 | |
parent | 0d87cb5b6757b81be4951c6aae20eb0c38999216 (diff) | |
download | openvswitch-995933f224d3f682541ef060a949986620df5f05.tar.gz |
ovn: Allow DNS lookups over IPv6
There was a bug in DNS request handling where the incoming packet was
assumed to be IPv4.
The result was that for the outgoing packet, we would attempt to write
the IPv4 checksum and total length into what was actually an IPv6
header. This resulted in the source IPv6 address getting corrupted.
Later, the source and destination IPv6 addresses would get swapped,
resulting in the DNS response being sent to a nonsense destination.
With this change, we check the ethertype of the packet to determine what
l3 information to write, and where to write it. A test is also included
that verifies that this works as expected.
Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=1539608
Signed-off-by: Mark Michelson <mmichels@redhat.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
-rw-r--r-- | ovn/controller/pinctrl.c | 17 | ||||
-rw-r--r-- | tests/ovn.at | 51 |
2 files changed, 63 insertions, 5 deletions
diff --git a/ovn/controller/pinctrl.c b/ovn/controller/pinctrl.c index af2ea15ea..2bc17c847 100644 --- a/ovn/controller/pinctrl.c +++ b/ovn/controller/pinctrl.c @@ -897,11 +897,18 @@ pinctrl_handle_dns_lookup( out_udp->udp_len = htons(new_l4_size); out_udp->udp_csum = 0; - struct ip_header *out_ip = dp_packet_l3(&pkt_out); - out_ip->ip_tot_len = htons(pkt_out.l4_ofs - pkt_out.l3_ofs + new_l4_size); - /* Checksum needs to be initialized to zero. */ - out_ip->ip_csum = 0; - out_ip->ip_csum = csum(out_ip, sizeof *out_ip); + struct eth_header *eth = dp_packet_data(&pkt_out); + if (eth->eth_type == htons(ETH_TYPE_IP)) { + struct ip_header *out_ip = dp_packet_l3(&pkt_out); + out_ip->ip_tot_len = htons(pkt_out.l4_ofs - pkt_out.l3_ofs + + new_l4_size); + /* Checksum needs to be initialized to zero. */ + out_ip->ip_csum = 0; + out_ip->ip_csum = csum(out_ip, sizeof *out_ip); + } else { + struct ovs_16aligned_ip6_hdr *nh = dp_packet_l3(&pkt_out); + nh->ip6_plen = htons(new_l4_size); + } pin->packet = dp_packet_data(&pkt_out); pin->packet_len = dp_packet_size(&pkt_out); diff --git a/tests/ovn.at b/tests/ovn.at index d825115b6..2355b9d40 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -6763,6 +6763,38 @@ test_dns() { as hv1 ovs-appctl netdev-dummy/receive hv1-vif$inport $request } +test_dns6() { + local inport=$1 src_mac=$2 dst_mac=$3 src_ip=$4 dst_ip=$5 dns_reply=$6 + local dns_query_data=$7 + shift; shift; shift; shift; shift; shift; shift; + # Packet size => UDP header (8) + + # DNS data (header + query) + ip_len=`expr 8 + ${#dns_query_data} / 2` + udp_len=$ip_len + ip_len=$(printf "%x" $ip_len) + udp_len=$(printf "%x" $udp_len) + local request=${dst_mac}${src_mac}86dd6000000000${ip_len}11ff${src_ip}${dst_ip} + request=${request}9234003500${udp_len}0000 + #dns data + request=${request}${dns_query_data} + + if test $dns_reply != 0; then + local dns_reply=$1 + ip_len=`expr 8 + ${#dns_reply} / 2` + udp_len=$ip_len + ip_len=$(printf "%x" $ip_len) + udp_len=$(printf "%x" $udp_len) + local reply=${src_mac}${dst_mac}86dd6000000000${ip_len}11ff${dst_ip}${src_ip} + reply=${reply}0035923400${udp_len}0000${dns_reply} + echo $reply >> $inport.expected + else + for outport; do + echo $request >> $outport.expected + done + fi + as hv1 ovs-appctl netdev-dummy/receive hv1-vif$inport $request +} + AT_CAPTURE_FILE([ofctl_monitor0.log]) as hv1 ovs-ofctl monitor br-int resume --detach --no-chdir \ --pidfile=ovs-ofctl0.pid 2> ofctl_monitor0.log @@ -6958,6 +6990,25 @@ reset_pcap_file hv1-vif2 hv1/vif2 rm -f 1.expected rm -f 2.expected +# Try DNS query over IPv6 +set_dns_params vm1 +src_ip=aef00000000000000000000000000004 +dst_ip=aef00000000000000000000000000001 +dns_reply=1 +test_dns6 1 f00000000001 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data $dns_resp_data + +# NXT_RESUMEs should be 9. +OVS_WAIT_UNTIL([test 9 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) + +$PYTHON "$top_srcdir/utilities/ovs-pcap.in" hv1/vif1-tx.pcap > 1.packets +cat 1.expected > expout +AT_CHECK([cat 1.packets], [0], [expout]) + +reset_pcap_file hv1-vif1 hv1/vif1 +reset_pcap_file hv1-vif2 hv1/vif2 +rm -f 1.expected +rm -f 2.expected + as hv1 OVS_APP_EXIT_AND_WAIT([ovn-controller]) OVS_APP_EXIT_AND_WAIT([ovs-vswitchd]) |