svn commit: r264905 - in head: sys/net sys/netinet sys/netinet6 tests/sys/netinet

Alan Somers asomers at FreeBSD.org
Thu Apr 24 23:56:59 UTC 2014


Author: asomers
Date: Thu Apr 24 23:56:56 2014
New Revision: 264905
URL: http://svnweb.freebsd.org/changeset/base/264905

Log:
  Fix subnet and default routes on different FIBs on the same subnet.
  
  These two bugs are closely related.  The root cause is that ifa_ifwithnet
  does not consider FIBs when searching for an interface address.
  
  sys/net/if_var.h
  sys/net/if.c
  	Add a fib argument to ifa_ifwithnet and ifa_ifwithdstadddr.  Those
  	functions will only return an address whose interface fib equals the
  	argument.
  
  sys/net/route.c
  	Update calls to ifa_ifwithnet and ifa_ifwithdstaddr with fib
  	arguments.
  
  sys/netinet/in.c
  	Update in_addprefix to consider the interface fib when adding
  	prefixes.  This will prevent it from not adding a subnet route when
  	one already exists on a different fib.
  
  sys/net/rtsock.c
  sys/netinet/in_pcb.c
  sys/netinet/ip_output.c
  sys/netinet/ip_options.c
  sys/netinet6/nd6.c
  	Add RT_DEFAULT_FIB arguments to ifa_ifwithdstaddr and ifa_ifwithnet.
  	In some cases it there wasn't a clear specific fib number to use.
  	In others, I was unable to test those functions so I chose
  	RT_DEFAULT_FIB to minimize divergence from current behavior.  I will
  	fix some of the latter changes along with PR kern/187553.
  
  tests/sys/netinet/fibs_test.sh
  tests/sys/netinet/udp_dontroute.c
  tests/sys/netinet/Makefile
  	Revert r263738.  The udp_dontroute test was right all along.
  	However, bugs kern/187550 and kern/187553 cancelled each other out
  	when it came to this test.  Because of kern/187553, ifa_ifwithnet
  	searched the default fib instead of the requested one, but because
  	of kern/187550, there was an applicable subnet route on the default
  	fib.  The new test added in r263738 doesn't work right, however.  I
  	can verify with dtrace that ifa_ifwithnet returned the wrong address
  	before I applied this commit, but route(8) miraculously found the
  	correct interface to use anyway.  I don't know how.
  
  	Clear expected failure messages for kern/187550 and kern/187552.
  
  PR:		kern/187550
  PR:		kern/187552
  Reviewed by:	melifaro
  MFC after:	3 weeks
  Sponsored by:	Spectra Logic

Added:
  head/tests/sys/netinet/udp_dontroute.c
     - copied unchanged from r263737, head/tests/sys/netinet/udp_dontroute.c
Modified:
  head/sys/net/if.c
  head/sys/net/if_var.h
  head/sys/net/route.c
  head/sys/net/rtsock.c
  head/sys/netinet/in.c
  head/sys/netinet/in_pcb.c
  head/sys/netinet/ip_options.c
  head/sys/netinet/ip_output.c
  head/sys/netinet6/nd6.c
  head/tests/sys/netinet/Makefile
  head/tests/sys/netinet/fibs_test.sh

Modified: head/sys/net/if.c
==============================================================================
--- head/sys/net/if.c	Thu Apr 24 23:28:09 2014	(r264904)
+++ head/sys/net/if.c	Thu Apr 24 23:56:56 2014	(r264905)
@@ -1653,7 +1653,7 @@ done:
  */
 /*ARGSUSED*/
 struct ifaddr *
-ifa_ifwithdstaddr(struct sockaddr *addr)
+ifa_ifwithdstaddr(struct sockaddr *addr, int fibnum)
 {
 	struct ifnet *ifp;
 	struct ifaddr *ifa;
@@ -1662,6 +1662,8 @@ ifa_ifwithdstaddr(struct sockaddr *addr)
 	TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
 			continue;
+		if ((ifp->if_fib != fibnum))
+			continue;
 		IF_ADDR_RLOCK(ifp);
 		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
 			if (ifa->ifa_addr->sa_family != addr->sa_family)
@@ -1686,7 +1688,7 @@ done:
  * is most specific found.
  */
 struct ifaddr *
-ifa_ifwithnet(struct sockaddr *addr, int ignore_ptp)
+ifa_ifwithnet(struct sockaddr *addr, int ignore_ptp, int fibnum)
 {
 	struct ifnet *ifp;
 	struct ifaddr *ifa;
@@ -1706,12 +1708,14 @@ ifa_ifwithnet(struct sockaddr *addr, int
 
 	/*
 	 * Scan though each interface, looking for ones that have addresses
-	 * in this address family.  Maintain a reference on ifa_maybe once
-	 * we find one, as we release the IF_ADDR_RLOCK() that kept it stable
-	 * when we move onto the next interface.
+	 * in this address family and the requested fib.  Maintain a reference
+	 * on ifa_maybe once we find one, as we release the IF_ADDR_RLOCK() that
+	 * kept it stable when we move onto the next interface.
 	 */
 	IFNET_RLOCK_NOSLEEP();
 	TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
+		if (ifp->if_fib != fibnum)
+			continue;
 		IF_ADDR_RLOCK(ifp);
 		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
 			char *cp, *cp2, *cp3;

Modified: head/sys/net/if_var.h
==============================================================================
--- head/sys/net/if_var.h	Thu Apr 24 23:28:09 2014	(r264904)
+++ head/sys/net/if_var.h	Thu Apr 24 23:56:56 2014	(r264905)
@@ -495,8 +495,8 @@ int	ifa_switch_loopback_route(struct ifa
 struct	ifaddr *ifa_ifwithaddr(struct sockaddr *);
 int		ifa_ifwithaddr_check(struct sockaddr *);
 struct	ifaddr *ifa_ifwithbroadaddr(struct sockaddr *);
-struct	ifaddr *ifa_ifwithdstaddr(struct sockaddr *);
-struct	ifaddr *ifa_ifwithnet(struct sockaddr *, int);
+struct	ifaddr *ifa_ifwithdstaddr(struct sockaddr *, int);
+struct	ifaddr *ifa_ifwithnet(struct sockaddr *, int, int);
 struct	ifaddr *ifa_ifwithroute(int, struct sockaddr *, struct sockaddr *);
 struct	ifaddr *ifa_ifwithroute_fib(int, struct sockaddr *, struct sockaddr *, u_int);
 struct	ifaddr *ifaof_ifpforaddr(struct sockaddr *, struct ifnet *);

Modified: head/sys/net/route.c
==============================================================================
--- head/sys/net/route.c	Thu Apr 24 23:28:09 2014	(r264904)
+++ head/sys/net/route.c	Thu Apr 24 23:56:56 2014	(r264905)
@@ -582,7 +582,7 @@ rtredirect_fib(struct sockaddr *dst,
 	}
 
 	/* verify the gateway is directly reachable */
-	if ((ifa = ifa_ifwithnet(gateway, 0)) == NULL) {
+	if ((ifa = ifa_ifwithnet(gateway, 0, fibnum)) == NULL) {
 		error = ENETUNREACH;
 		goto out;
 	}
@@ -739,7 +739,7 @@ ifa_ifwithroute_fib(int flags, struct so
 		 */
 		ifa = NULL;
 		if (flags & RTF_HOST)
-			ifa = ifa_ifwithdstaddr(dst);
+			ifa = ifa_ifwithdstaddr(dst, fibnum);
 		if (ifa == NULL)
 			ifa = ifa_ifwithaddr(gateway);
 	} else {
@@ -748,10 +748,10 @@ ifa_ifwithroute_fib(int flags, struct so
 		 * or host, the gateway may still be on the
 		 * other end of a pt to pt link.
 		 */
-		ifa = ifa_ifwithdstaddr(gateway);
+		ifa = ifa_ifwithdstaddr(gateway, fibnum);
 	}
 	if (ifa == NULL)
-		ifa = ifa_ifwithnet(gateway, 0);
+		ifa = ifa_ifwithnet(gateway, 0, fibnum);
 	if (ifa == NULL) {
 		struct rtentry *rt = rtalloc1_fib(gateway, 0, RTF_RNH_LOCKED, fibnum);
 		if (rt == NULL)
@@ -865,7 +865,7 @@ rt_getifa_fib(struct rt_addrinfo *info, 
 	 */
 	if (info->rti_ifp == NULL && ifpaddr != NULL &&
 	    ifpaddr->sa_family == AF_LINK &&
-	    (ifa = ifa_ifwithnet(ifpaddr, 0)) != NULL) {
+	    (ifa = ifa_ifwithnet(ifpaddr, 0, fibnum)) != NULL) {
 		info->rti_ifp = ifa->ifa_ifp;
 		ifa_free(ifa);
 	}

Modified: head/sys/net/rtsock.c
==============================================================================
--- head/sys/net/rtsock.c	Thu Apr 24 23:28:09 2014	(r264904)
+++ head/sys/net/rtsock.c	Thu Apr 24 23:56:56 2014	(r264905)
@@ -735,7 +735,8 @@ route_output(struct mbuf *m, struct sock
 			    rt->rt_ifp->if_type == IFT_PROPVIRTUAL) {
 				struct ifaddr *ifa;
 
-				ifa = ifa_ifwithnet(info.rti_info[RTAX_DST], 1);
+				ifa = ifa_ifwithnet(info.rti_info[RTAX_DST], 1,
+				    RT_DEFAULT_FIB);
 				if (ifa != NULL)
 					rt_maskedcopy(ifa->ifa_addr,
 						      &laddr,

Modified: head/sys/netinet/in.c
==============================================================================
--- head/sys/netinet/in.c	Thu Apr 24 23:28:09 2014	(r264904)
+++ head/sys/netinet/in.c	Thu Apr 24 23:56:56 2014	(r264905)
@@ -617,7 +617,7 @@ in_addprefix(struct in_ifaddr *target, i
 {
 	struct in_ifaddr *ia;
 	struct in_addr prefix, mask, p, m;
-	int error, fibnum;
+	int error;
 
 	if ((flags & RTF_HOST) != 0) {
 		prefix = target->ia_dstaddr.sin_addr;
@@ -628,9 +628,8 @@ in_addprefix(struct in_ifaddr *target, i
 		prefix.s_addr &= mask.s_addr;
 	}
 
-	fibnum = rt_add_addr_allfibs ? RT_ALL_FIBS : target->ia_ifp->if_fib;
-
 	IN_IFADDR_RLOCK();
+	/* Look for an existing address with the same prefix, mask, and fib */
 	TAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) {
 		if (rtinitflags(ia)) {
 			p = ia->ia_dstaddr.sin_addr;
@@ -646,6 +645,8 @@ in_addprefix(struct in_ifaddr *target, i
 			    mask.s_addr != m.s_addr)
 				continue;
 		}
+		if (target->ia_ifp->if_fib != ia->ia_ifp->if_fib)
+			continue;
 
 		/*
 		 * If we got a matching prefix route inserted by other
@@ -664,6 +665,10 @@ in_addprefix(struct in_ifaddr *target, i
 				IN_IFADDR_RUNLOCK();
 				return (EEXIST);
 			} else {
+				int fibnum;
+
+				fibnum = rt_add_addr_allfibs ? RT_ALL_FIBS :
+					target->ia_ifp->if_fib;
 				rt_addrmsg(RTM_ADD, &target->ia_ifa, fibnum);
 				IN_IFADDR_RUNLOCK();
 				return (0);

Modified: head/sys/netinet/in_pcb.c
==============================================================================
--- head/sys/netinet/in_pcb.c	Thu Apr 24 23:28:09 2014	(r264904)
+++ head/sys/netinet/in_pcb.c	Thu Apr 24 23:56:56 2014	(r264905)
@@ -745,9 +745,11 @@ in_pcbladdr(struct inpcb *inp, struct in
 		struct in_ifaddr *ia;
 		struct ifnet *ifp;
 
-		ia = ifatoia(ifa_ifwithdstaddr((struct sockaddr *)sin));
+		ia = ifatoia(ifa_ifwithdstaddr((struct sockaddr *)sin,
+		    RT_DEFAULT_FIB));
 		if (ia == NULL)
-			ia = ifatoia(ifa_ifwithnet((struct sockaddr *)sin, 0));
+			ia = ifatoia(ifa_ifwithnet((struct sockaddr *)sin, 0,
+			    RT_DEFAULT_FIB));
 		if (ia == NULL) {
 			error = ENETUNREACH;
 			goto done;
@@ -862,9 +864,10 @@ in_pcbladdr(struct inpcb *inp, struct in
 		sain.sin_len = sizeof(struct sockaddr_in);
 		sain.sin_addr.s_addr = faddr->s_addr;
 
-		ia = ifatoia(ifa_ifwithdstaddr(sintosa(&sain)));
+		ia = ifatoia(ifa_ifwithdstaddr(sintosa(&sain), RT_DEFAULT_FIB));
 		if (ia == NULL)
-			ia = ifatoia(ifa_ifwithnet(sintosa(&sain), 0));
+			ia = ifatoia(ifa_ifwithnet(sintosa(&sain), 0,
+			    RT_DEFAULT_FIB));
 		if (ia == NULL)
 			ia = ifatoia(ifa_ifwithaddr(sintosa(&sain)));
 

Modified: head/sys/netinet/ip_options.c
==============================================================================
--- head/sys/netinet/ip_options.c	Thu Apr 24 23:28:09 2014	(r264904)
+++ head/sys/netinet/ip_options.c	Thu Apr 24 23:56:56 2014	(r264905)
@@ -227,8 +227,11 @@ dropit:
 			if (opt == IPOPT_SSRR) {
 #define	INA	struct in_ifaddr *
 #define	SA	struct sockaddr *
-			    if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == NULL)
-				    ia = (INA)ifa_ifwithnet((SA)&ipaddr, 0);
+			    if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr,
+				RT_DEFAULT_FIB)) == NULL) {
+				    ia = (INA)ifa_ifwithnet((SA)&ipaddr, 0,
+					RT_DEFAULT_FIB);
+			    }
 			} else
 /* XXX MRT 0 for routing */
 				ia = ip_rtaddr(ipaddr.sin_addr, M_GETFIB(m));

Modified: head/sys/netinet/ip_output.c
==============================================================================
--- head/sys/netinet/ip_output.c	Thu Apr 24 23:28:09 2014	(r264904)
+++ head/sys/netinet/ip_output.c	Thu Apr 24 23:56:56 2014	(r264905)
@@ -230,7 +230,8 @@ again:
 	 */
 	if (flags & IP_SENDONES) {
 		if ((ia = ifatoia(ifa_ifwithbroadaddr(sintosa(dst)))) == NULL &&
-		    (ia = ifatoia(ifa_ifwithdstaddr(sintosa(dst)))) == NULL) {
+		    (ia = ifatoia(ifa_ifwithdstaddr(sintosa(dst),
+						    RT_DEFAULT_FIB))) == NULL) {
 			IPSTAT_INC(ips_noroute);
 			error = ENETUNREACH;
 			goto bad;
@@ -241,8 +242,10 @@ again:
 		ip->ip_ttl = 1;
 		isbroadcast = 1;
 	} else if (flags & IP_ROUTETOIF) {
-		if ((ia = ifatoia(ifa_ifwithdstaddr(sintosa(dst)))) == NULL &&
-		    (ia = ifatoia(ifa_ifwithnet(sintosa(dst), 0))) == NULL) {
+		if ((ia = ifatoia(ifa_ifwithdstaddr(sintosa(dst),
+		    				    RT_DEFAULT_FIB))) == NULL &&
+		    (ia = ifatoia(ifa_ifwithnet(sintosa(dst), 0,
+		    				RT_DEFAULT_FIB))) == NULL) {
 			IPSTAT_INC(ips_noroute);
 			error = ENETUNREACH;
 			goto bad;

Modified: head/sys/netinet6/nd6.c
==============================================================================
--- head/sys/netinet6/nd6.c	Thu Apr 24 23:28:09 2014	(r264904)
+++ head/sys/netinet6/nd6.c	Thu Apr 24 23:56:56 2014	(r264905)
@@ -945,7 +945,7 @@ nd6_is_new_addr_neighbor(struct sockaddr
 	 * If the address is assigned on the node of the other side of
 	 * a p2p interface, the address should be a neighbor.
 	 */
-	dstaddr = ifa_ifwithdstaddr((struct sockaddr *)addr);
+	dstaddr = ifa_ifwithdstaddr((struct sockaddr *)addr, RT_DEFAULT_FIB);
 	if (dstaddr != NULL) {
 		if (dstaddr->ifa_ifp == ifp) {
 			ifa_free(dstaddr);

Modified: head/tests/sys/netinet/Makefile
==============================================================================
--- head/tests/sys/netinet/Makefile	Thu Apr 24 23:28:09 2014	(r264904)
+++ head/tests/sys/netinet/Makefile	Thu Apr 24 23:56:56 2014	(r264905)
@@ -1,7 +1,12 @@
 # $FreeBSD$
 
 TESTSDIR=	${TESTSBASE}/sys/netinet
+BINDIR=		${TESTSDIR}
 
 ATF_TESTS_SH+=	fibs_test
+PROG=	udp_dontroute
+SRCS=	udp_dontroute.c
+NO_MAN=
+WARNS?=	6
 
 .include <bsd.test.mk>

Modified: head/tests/sys/netinet/fibs_test.sh
==============================================================================
--- head/tests/sys/netinet/fibs_test.sh	Thu Apr 24 23:28:09 2014	(r264904)
+++ head/tests/sys/netinet/fibs_test.sh	Thu Apr 24 23:56:56 2014	(r264905)
@@ -175,7 +175,6 @@ default_route_with_multiple_fibs_on_same
 
 default_route_with_multiple_fibs_on_same_subnet_body()
 {
-	atf_expect_fail "kern/187552 default route uses the wrong interface when multiple interfaces have the same subnet but different fibs"
 	# Configure the TAP interfaces to use a RFC5737 nonrouteable addresses
 	# and a non-default fib
 	ADDR0="192.0.2.2"
@@ -225,7 +224,6 @@ subnet_route_with_multiple_fibs_on_same_
 
 subnet_route_with_multiple_fibs_on_same_subnet_body()
 {
-	atf_expect_fail "kern/187550 Multiple interfaces on different FIBs but the same subnet don't all have a subnet route"
 	# Configure the TAP interfaces to use a RFC5737 nonrouteable addresses
 	# and a non-default fib
 	ADDR0="192.0.2.2"
@@ -253,66 +251,54 @@ subnet_route_with_multiple_fibs_on_same_
 	cleanup_tap
 }
 
-# Regression test for kern/187553 "Source address selection for UDP packets
-# with SO_DONTROUTE uses the default FIB".  The original complaint was that a
-# UDP packet with SO_DONTROUTE set would select a source address from an
-# interface on the default FIB instead of the process FIB.
+# Test that source address selection works correctly for UDP packets with
+# SO_DONTROUTE set that are sent on non-default FIBs.
 # This bug was discovered with "setfib 1 netperf -t UDP_STREAM -H some_host"
 # Regression test for kern/187553
-
+#
 # The root cause was that ifa_ifwithnet() did not have a fib argument.  It
 # would return an address from an interface on any FIB that had a subnet route
 # for the destination.  If more than one were available, it would choose the
-# most specific.  The root cause is most easily tested by creating two
-# interfaces with overlapping subnet routes, adding a default route to the
-# interface with the less specific subnet route, and looking up a host that
-# requires the default route using the FIB of the interface with the less
-# specific subnet route.  "route get" should provide a route that uses the
-# interface on the chosen FIB.  However, absent the patch for this bug it will
-# instead use the other interface.
-atf_test_case src_addr_selection_by_subnet cleanup
-src_addr_selection_by_subnet_head()
+# most specific.  This is most easily tested by creating a FIB without a
+# default route, then trying to send a UDP packet with SO_DONTROUTE set to an
+# address which is not routable on that FIB.  Absent the fix for this bug,
+# in_pcbladdr would choose an interface on any FIB with a default route.  With
+# the fix, you will get EUNREACH or ENETUNREACH.
+atf_test_case udp_dontroute cleanup
+udp_dontroute_head()
 {
 	atf_set "descr" "Source address selection for UDP packets with SO_DONTROUTE on non-default FIBs works"
 	atf_set "require.user" "root"
 	atf_set "require.config" "fibs"
 }
 
-src_addr_selection_by_subnet_body()
+udp_dontroute_body()
 {
 	atf_expect_fail "kern/187553 Source address selection for UDP packets with SO_DONTROUTE uses the default FIB"
 	# Configure the TAP interface to use an RFC5737 nonrouteable address
 	# and a non-default fib
-	ADDR0="192.0.2.2"
-	ADDR1="192.0.2.3"
-	GATEWAY0="192.0.2.1"
-	TARGET="192.0.2.128"
+	ADDR="192.0.2.2"
 	SUBNET="192.0.2.0"
-	MASK0="25"
-	MASK1="26"
+	MASK="24"
+	# Use a different IP on the same subnet as the target
+	TARGET="192.0.2.100"
 
 	# Check system configuration
 	if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then
 		atf_skip "This test requires net.add_addr_allfibs=0"
 	fi
-	get_fibs 2
+	get_fibs 1
 
 	# Configure a TAP interface
-	setup_tap ${FIB0} ${ADDR0} ${MASK0}
-	TAP0=${TAP}
-	setup_tap ${FIB1} ${ADDR1} ${MASK1}
-	TAP1=${TAP}
-
-	# Add a gateway to the interface with the less specific subnet route
-	setfib ${FIB0} route add default ${GATEWAY0}
+	setup_tap ${FIB0} ${ADDR} ${MASK}
 
-	# Lookup a route
-	echo "Looking up route to ${TARGET} with fib ${FIB0}"
-	echo "Expected behavior is to use interface ${TAP0}"
-	atf_check -o match:"interface:.${TAP0}" setfib ${FIB0} route -n get ${TARGET}
+	# Send a UDP packet with SO_DONTROUTE.  In the failure case, it will
+	# return ENETUNREACH
+	SRCDIR=`atf_get_srcdir`
+	atf_check -o ignore setfib ${FIB0} ${SRCDIR}/udp_dontroute ${TARGET}
 }
 
-src_addr_selection_by_subnet_cleanup()
+udp_dontroute_cleanup()
 {
 	cleanup_tap
 }
@@ -324,7 +310,7 @@ atf_init_test_cases()
 	atf_add_test_case loopback_and_network_routes_on_nondefault_fib 
 	atf_add_test_case default_route_with_multiple_fibs_on_same_subnet 
 	atf_add_test_case subnet_route_with_multiple_fibs_on_same_subnet 
-	atf_add_test_case src_addr_selection_by_subnet
+	atf_add_test_case udp_dontroute
 }
 
 # Looks up one or more fibs from the configuration data and validates them.

Copied: head/tests/sys/netinet/udp_dontroute.c (from r263737, head/tests/sys/netinet/udp_dontroute.c)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/tests/sys/netinet/udp_dontroute.c	Thu Apr 24 23:56:56 2014	(r264905, copy of r263737, head/tests/sys/netinet/udp_dontroute.c)
@@ -0,0 +1,85 @@
+/*
+ *  Copyright (c) 2014 Spectra Logic Corporation
+ *  All rights reserved.
+ * 
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions, and the following disclaimer,
+ *     without modification.
+ *  2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *     substantially similar to the "NO WARRANTY" disclaimer below
+ *     ("Disclaimer") and any redistribution must be conditioned upon
+ *     including a substantially similar Disclaimer requirement for further
+ *     binary redistribution.
+ * 
+ *  NO WARRANTY
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *  HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ *  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ *  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ *  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ *  IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *  POSSIBILITY OF SUCH DAMAGES.
+ * 
+ *  Authors: Alan Somers         (Spectra Logic Corporation)
+ *
+ * $FreeBSD$
+ */
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* 
+ * Sends a single UDP packet to the provided address, with SO_DONTROUTE set
+ * I couldn't find a way to do this with builtin utilities like nc(1)
+ */
+int main(int argc, char **argv)
+{
+	struct sockaddr_in dst;
+	int s;
+	int opt;
+	int ret;
+	const char* buf = "Hello, World!";
+
+	if (argc != 2) {
+		fprintf(stderr, "Usage: %s ip_address\n", argv[0]);
+		exit(2);
+	}
+	s = socket(PF_INET, SOCK_DGRAM, 0);
+	if (s < 0)
+		err(errno, "socket");
+	opt = 1;
+
+	ret = setsockopt(s, SOL_SOCKET, SO_DONTROUTE, &opt, sizeof(opt));
+	if (ret == -1)
+		err(errno, "setsockopt(SO_DONTROUTE)");
+
+	dst.sin_len = sizeof(dst);
+	dst.sin_family = AF_INET;
+	dst.sin_port = htons(46120);
+	dst.sin_addr.s_addr = inet_addr(argv[1]);
+	if (dst.sin_addr.s_addr == htonl(INADDR_NONE)) {
+		fprintf(stderr, "Invalid address: %s\n", argv[1]);
+		exit(2);
+	}
+	ret = sendto(s, buf, strlen(buf), 0, (struct sockaddr*)&dst,
+	    dst.sin_len);
+	if (ret == -1)
+		err(errno, "sendto");
+	
+	return (0);
+}


More information about the svn-src-all mailing list