From owner-svn-src-all@FreeBSD.ORG Thu Apr 24 23:56:59 2014 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id A9B727AE; Thu, 24 Apr 2014 23:56:59 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 94CAA10E4; Thu, 24 Apr 2014 23:56:59 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.8/8.14.8) with ESMTP id s3ONuxtA009073; Thu, 24 Apr 2014 23:56:59 GMT (envelope-from asomers@svn.freebsd.org) Received: (from asomers@localhost) by svn.freebsd.org (8.14.8/8.14.8/Submit) id s3ONuvej009057; Thu, 24 Apr 2014 23:56:57 GMT (envelope-from asomers@svn.freebsd.org) Message-Id: <201404242356.s3ONuvej009057@svn.freebsd.org> From: Alan Somers Date: Thu, 24 Apr 2014 23:56:57 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r264905 - in head: sys/net sys/netinet sys/netinet6 tests/sys/netinet X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.17 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 24 Apr 2014 23:56:59 -0000 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 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 +#include +#include +#include + +#include +#include +#include +#include +#include + +/* + * 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); +}