Date: Mon, 8 Mar 2004 20:22:13 +0000 From: Bruce M Simpson <bms@spc.org> To: Jerry Jensen <youknicks@yahoo.com> Cc: freebsd-net@freebsd.org Subject: Re: multiple logical interfaces Message-ID: <20040308202213.GP826@saboteur.dek.spc.org> In-Reply-To: <20040308091935.59513.qmail@web41811.mail.yahoo.com> References: <1078642138.728121.16568.nullmailer@cicuta.babolo.ru> <20040308091935.59513.qmail@web41811.mail.yahoo.com>
next in thread | previous in thread | raw e-mail | index | archive | help
--Y7xTucakfITjPcLV Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Mon, Mar 08, 2004 at 01:19:35AM -0800, Jerry Jensen wrote: > How can this be done programmatically rather than from > the command line? Code snippets would be handy. This should contain the snippets you need for instantiating cloneable interfaces, including ds(4) and lo(4). BMS --Y7xTucakfITjPcLV Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="rtmhack.c" /* $FreeBSD$ */ /* * This is a hack to demonstrate the concept of hooking for the * RTM_RESOLVE message being sent from the FreeBSD routing code, * as a means of looking up routes on demand using a routing protocol * such as AODV. * This code will probably be vastly cleaned up and tested more thoroughly * before being used as the basis for a user-space BSD AODV implementation. */ /* * Copyright (c) 2003 Bruce M. Simpson <bms@spc.org> * 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. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Bruce M. Simpson. * 4. Neither the name of Bruce M. Simpson nor the names of co- * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY Bruce M. Simpson AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Bruce M. Simpson OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 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 DAMAGE. */ #include <sys/param.h> #include <sys/file.h> #include <sys/socket.h> #include <sys/sysctl.h> #include <sys/ioctl.h> #include <sys/sysctl.h> #include <sys/types.h> #include <sys/signal.h> #include <net/if.h> #include <net/if_var.h> #include <net/if_mib.h> #include <net/if_types.h> #include <net/if_dl.h> #include <net/route.h> #include <netinet/in.h> #include <netinet/if_ether.h> #include <arpa/inet.h> #include <netdb.h> #include <ctype.h> #include <err.h> #include <errno.h> #include <paths.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sysexits.h> #include <unistd.h> #include <ifaddrs.h> union sockunion { struct sockaddr sa; struct sockaddr_in sin; struct sockaddr_dl sdl; struct sockaddr_storage ss; }; typedef union sockunion sockunion_t; void usage(void); int add_xresolve_route(char *ifname, struct sockaddr_in *sin, int bits); int inet_cidr_aton(char *s, struct in_addr *pin, int *bits); int create_if(char *ifname); int destroy_if(char *ifname); int if2sockaddr(char *ifname, struct sockaddr_dl *sdl); int handle_rtmsg(struct rt_msghdr *rtm, int msglen); int handle_rtmsg_resolve(struct rt_msghdr *rtm, int msglen); int reply_rtmsg_resolve(struct sockaddr_in *sin); /* * We check for the existence of ifname. */ #if 1 #define _IFNAME "disc1" #else #define _IFNAME "lo0" #endif int rtsock = -1; int created = 0; char *ifname = _IFNAME; void sighand_term(int sig) { /* * Destroying an interface is sufficient to delete the routes * pointing to it. */ if (created) destroy_if(ifname); exit(EXIT_SUCCESS); } void setup_signals(void) { struct sigaction sa, osa; sa.sa_handler = sighand_term; sa.sa_flags = 0; sigemptyset(&sa.sa_mask); sigaction(SIGTERM, &sa, &osa); sigaction(SIGINT, &sa, &osa); sigaction(SIGQUIT, &sa, &osa); sigaction(SIGKILL, &sa, &osa); } int main(int argc, char *argv[]) { int n; int bits; char msg[2048]; struct sockaddr_in sin; if (geteuid() != 0) errx(1, "must be root to alter routing table"); memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_len = sizeof(sin); /* Parse network argument */ if ((argc != 2) || (inet_cidr_aton(argv[1], &sin.sin_addr, &bits) != 1)) usage(); setup_signals(); /* Open routing socket */ rtsock = socket(PF_ROUTE, SOCK_RAW, 0); if (rtsock == -1) err(EX_OSERR, "socket"); /* Check that the target interface exists; create it if it doesn't. */ if (if_nametoindex(ifname) == 0) { warnx("interface %s does not exist, creating.", ifname); create_if(ifname); created = 1; add_xresolve_route(ifname, &sin, bits); } /* Routing event loop */ for (;;) { n = read(rtsock, msg, sizeof(msg)); handle_rtmsg((struct rt_msghdr *)msg, n); } if (rtsock != -1) close(rtsock); exit (EXIT_SUCCESS); } void usage(void) { fprintf(stderr, "usage: rtmhack <testnet>\n" "<testnet> specifies the test network in CIDR notation\n"); exit(EXIT_FAILURE); } /* * Like inet_aton(), but handle an optional CIDR prefix. */ int inet_cidr_aton(char *s, struct in_addr *pin, int *bits) { char *q; q = NULL; *bits = 32; if ((q = strchr(s, '/')) != NULL) { *bits = strtoul(q+1, 0, 0); *q = '\0'; } return (inet_aton(s, pin)); } /* * create an instance of a named clonable interface. * Return 0 if successful, or -1 if an error occurred. */ int create_if(char *ifname) { int s, retval; struct ifreq ifr; retval = 0; s = socket(AF_INET, SOCK_DGRAM, 0); if (s == -1) err(1, "socket"); memset(&ifr, 0, sizeof(ifr)); (void) strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); if (ioctl(s, SIOCIFCREATE, &ifr) < 0) { retval = -1; warn("SIOCIFCREATE"); } close(s); return (retval); } /* * destroy an instance of a named clonable interface. * Return 0 if successful, or -1 if an error occurred. */ int destroy_if(char *ifname) { int s, retval; struct ifreq ifr; retval = 0; s = socket(AF_INET, SOCK_DGRAM, 0); if (s == -1) err(1, "socket"); memset(&ifr, 0, sizeof(ifr)); (void) strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); if (ioctl(s, SIOCIFDESTROY, &ifr) < 0) { retval = -1; warn("SIOCIFDESTROY"); } close(s); return (retval); } /* * Copy the sockaddr_dl structure corresponding to the named interface * into the structure pointed to by sdl. * Returns 0 if successful, or -1 if the structure found was not valid. */ int if2sockaddr(char *ifname, struct sockaddr_dl *sdl) { struct ifaddrs *ifap, *ifa; struct sockaddr_dl *isdl; if (getifaddrs(&ifap)) err(1, "getifaddrs"); isdl = NULL; for (ifa = ifap; ifa; ifa = ifa->ifa_next) { if (ifa->ifa_addr->sa_family != AF_LINK) continue; if (strcmp(ifname, ifa->ifa_name)) continue; isdl = (struct sockaddr_dl *)ifa->ifa_addr; } if (isdl) memcpy(sdl, isdl, isdl->sdl_len); return ((isdl != NULL) ? 0 : -1); } /* * Given the prefix length of an IPv4 CIDR network address, * fill out a sockaddr_in structure accordingly for use with * BSD routing code. * * Return the value of the sin_len member as a hint. */ int inet_makenetmask(int bits, struct sockaddr_in *so_mask) { char *cp; unsigned long mask; int len; const int maxbits = 32; memset(so_mask, 0, sizeof(struct sockaddr_in)); mask = 0xFFFFFFFF << (maxbits - bits); so_mask->sin_addr.s_addr = htonl(mask); /* count number of bytes in mask containing set bits */ cp = (char *)(&so_mask->sin_addr + 1); while (*--cp == 0 && cp > (char *)&so_mask) ; so_mask->sin_len = len = 1 + cp - (char *)&so_mask; return (len); } /* * Bind an cloning XRESOLVE route, for the given network/host, * to a named interface. * * The packing of the rtm message is all important. The kernel * expects it in a certain way. This routine seems to work but * 'route monitor' is reporting some junk at the end of the netmask. * * Return 0 if successful, or -1 if an error occurred. */ int add_xresolve_route(char *ifname, struct sockaddr_in *so_dst, int bits) { #define ROUNDUP(a) \ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) #define NEXTADDR(cp, l, u) \ do { \ l = (u)->sa.sa_len; \ (l) = ROUNDUP(l); \ memmove((cp), (u), (l)); \ (cp) += (l); \ } while (0) /* */ struct { struct rt_msghdr rtm; sockunion_t addrs[RTAX_MAX]; } r; sockunion_t so_iface; sockunion_t so_mask; int rlen, len, masklen; char *cp; cp = (char *)&r.addrs[0]; masklen = rlen = len = 0; memset(&r, 0, sizeof(r)); memset(&so_iface, 0, sizeof(so_iface)); memset(&so_mask, 0, sizeof(so_mask)); r.rtm.rtm_version = RTM_VERSION; r.rtm.rtm_type = RTM_ADD; r.rtm.rtm_pid = getpid(); r.rtm.rtm_seq = 0; r.rtm.rtm_flags = RTF_XRESOLVE | RTF_CLONING | RTF_UP; r.rtm.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; if2sockaddr(ifname, &so_iface.sdl); masklen = inet_makenetmask(bits, &so_mask.sin); NEXTADDR(cp, len, (sockunion_t *)so_dst); NEXTADDR(cp, len, &so_iface); NEXTADDR(cp, len, &so_mask); r.rtm.rtm_msglen = len = cp - (char *)&r; rlen = write(rtsock, &r, len); if (rlen < 0) warn("write"); return ((rlen > 0) ? 0 : -1); #undef NEXTADDR #undef ROUNDUP } /* * routing socket message dispatcher */ int handle_rtmsg(struct rt_msghdr *rtm, int msglen) { if (rtm->rtm_version != RTM_VERSION) { (void) printf("bad routing message version %d\n", rtm->rtm_version); return (-1); } switch (rtm->rtm_type) { case RTM_RESOLVE: (void) printf("rtm_type %d: RTM_RESOLVE\n", rtm->rtm_type); handle_rtmsg_resolve(rtm, msglen); break; default: (void) printf("rtm_type %d: ignored\n", rtm->rtm_type); } return (0); } /* * Dispatch routine for RTM_RESOLVE routing messages. * Return 0 if successful; otherwise, return -1 if an error occurred. */ int handle_rtmsg_resolve(struct rt_msghdr *rtm, int msglen) { struct sockaddr_in *sin; struct sockaddr *sa; void *sp; /* * ignore messages from ourselves */ if (rtm->rtm_pid == getpid()) { printf("heard own message, ignoring\n"); return (0); } printf("rtm_index: %04x rtm_addrs: %08x\n", rtm->rtm_index, rtm->rtm_addrs); /* * The message must contain the address for which a route is * being requested, otherwise it is invalid. */ if (!(rtm->rtm_addrs & RTA_DST)) { warnx("RTM_RESOLVE message does not contain destination"); return (-1); } sa = sp = (rtm + 1); if (sa->sa_family != AF_INET) { warnx("RTM_RESOLVE contains non-AF_INET destination %d", sa->sa_family); return (-1); } sin = (struct sockaddr_in *)sa; printf("route requested for %s\n", inet_ntoa(sin->sin_addr)); /* * XXX: Should check if the requested destination is within the * network prefix specified on the command line. */ reply_rtmsg_resolve(sin); printf("route resolved for %s\n", inet_ntoa(sin->sin_addr)); return (0); } /* * Modify a given route in response to an RTM_RESOLVE message from the kernel. * Return 0 if successful; otherwise, return -1. */ int reply_rtmsg_resolve(struct sockaddr_in *sin) { struct { struct rt_msghdr rtm; struct sockaddr addrs[RTAX_MAX]; } r; struct sockaddr_dl sdl; int len; memset(&r, 0, sizeof(r)); r.rtm.rtm_version = RTM_VERSION; r.rtm.rtm_type = RTM_CHANGE; r.rtm.rtm_pid = getpid(); r.rtm.rtm_seq = 0; if2sockaddr("lo0", &sdl); memcpy(&r.addrs[RTAX_DST], sin, sin->sin_len); memcpy(&r.addrs[RTAX_GATEWAY], &sdl, sdl.sdl_len); memset(&r.addrs[RTAX_IFP], 0, sizeof(r.addrs[RTAX_IFP])); memset(&r.addrs[RTAX_IFA], 0, sizeof(r.addrs[RTAX_IFA])); r.rtm.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_IFP | RTA_IFA; r.rtm.rtm_flags = RTF_DONE; r.rtm.rtm_msglen = sizeof(r); len = write(rtsock, &r, r.rtm.rtm_msglen); if (len != r.rtm.rtm_msglen) warn("write"); return ((len > 0) ? 0 : -1); } --Y7xTucakfITjPcLV--
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20040308202213.GP826>