This is a really inefficient but quick alteration I made to DHCPv6 to make it serve several network interfaces indepenently. I.e. you can serve 6to4 or native addresses on eth0 to your internal lan and RFC4193 addresses on a hostap wlan0 node (for Free Network participation) if you run dhcp6s -Df -x :: eth0 wlan0 we read /etc/wide-dhcpv6/dhcp6s.conf.eth0 or /etc/wide-dhcpv6/dhcp6s.conf.wlan0 http://www.wensley.org.uk/patches/wide-dhcpv6-20061016.patch --- wide-dhcpv6-20061016/dhcp6s.c 2006-08-07 05:35:32.000000000 +0100 +++ wide-dhcpv6-20061016/dhcp6s.c 2007-02-02 19:38:25.000000000 +0000 @@ -128,13 +128,12 @@ #define SIGF_TERM 0x1 const dhcp6_mode_t dhcp6_mode = DHCP6_MODE_SERVER; -char *device = NULL; -int ifidx; int insock; /* inbound UDP port */ int outsock; /* outbound UDP port */ int ctlsock = -1; /* control TCP port */ char *ctladdr = DEFAULT_SERVER_CONTROL_ADDR; char *ctlport = DEFAULT_SERVER_CONTROL_PORT; +static char* nodeaddr = NULL; static const struct sockaddr_in6 *sa6_any_downstream, *sa6_any_relay; static struct msghdr rmh; @@ -153,7 +152,7 @@ static inline int get_val __P((char **, int *, void *, size_t)); static void usage __P((void)); -static void server6_init __P((void)); +static void server6_init __P((int, char **)); static void server6_mainloop __P((void)); static int server6_do_ctlcommand __P((char *, ssize_t)); static void server6_reload __P((void)); @@ -243,7 +242,7 @@ TAILQ_INIT(&bcmcsnamelist); srandom(time(NULL) & getpid()); - while ((ch = getopt(argc, argv, "c:dDfk:n:p:P:")) != -1) { + while ((ch = getopt(argc, argv, "c:dDfk:n:p:P:x:")) != -1) { switch (ch) { case 'c': conffile = optarg; @@ -274,11 +273,20 @@ dlv->val_addr6 = a; TAILQ_INSERT_TAIL(&arg_dnslist, dlv, link); break; + case 'x': + nodeaddr = malloc(strlen(optarg)); + if (nodeaddr != NULL) { + strcpy(nodeaddr, optarg); + } else { + fprintf(stderr, "cannot allocate ram for nodeaddr!\n"); + } + break; case 'p': ctlport = optarg; break; case 'P': pid_file = optarg; + break; default: usage(); /* NOTREACHED */ @@ -287,20 +295,21 @@ argc -= optind; argv += optind; + /* if (argc != 1) { usage(); - /* NOTREACHED */ } - device = argv[0]; + */ + /* device = argv[0]; */ if (foreground == 0) openlog(progname, LOG_NDELAY|LOG_PID, LOG_DAEMON); setloglevel(debug); - if (ifinit(device) == NULL) + /* if (ifinit(device) == NULL) exit(1); - + */ if ((cfparse(conffile)) != 0) { dprintf(LOG_ERR, FNAME, "failed to parse configuration file"); exit(1); @@ -329,7 +338,7 @@ TAILQ_INIT(&arg_dnslist); } - server6_init(); + server6_init(argc, argv); server6_mainloop(); exit(0); @@ -347,11 +356,11 @@ /*------------------------------------------------------------*/ void -server6_init() +server6_init(int argc, char** argv) { struct addrinfo hints; struct addrinfo *res, *res2; - int error; + int error, i; int on = 1; struct ipv6_mreq mreq6; static struct iovec iov; @@ -364,12 +373,6 @@ exit(1); } - ifidx = if_nametoindex(device); - if (ifidx == 0) { - dprintf(LOG_ERR, FNAME, "invalid interface %s", device); - exit(1); - } - /* get our DUID */ if (get_duid(DUID_FILE, &server_duid)) { dprintf(LOG_ERR, FNAME, "failed to get a DUID"); @@ -399,9 +402,9 @@ hints.ai_socktype = SOCK_DGRAM; hints.ai_protocol = IPPROTO_UDP; hints.ai_flags = AI_PASSIVE; - error = getaddrinfo(NULL, DH6PORT_UPSTREAM, &hints, &res); + error = getaddrinfo(nodeaddr, DH6PORT_UPSTREAM, &hints, &res); if (error) { - dprintf(LOG_ERR, FNAME, "getaddrinfo: %s", + dprintf(LOG_ERR, FNAME, "Uplink getaddrinfo: %s", gai_strerror(error)); exit(1); } @@ -455,21 +458,25 @@ hints.ai_flags = 0; error = getaddrinfo(DH6ADDR_ALLAGENT, DH6PORT_UPSTREAM, &hints, &res2); if (error) { - dprintf(LOG_ERR, FNAME, "getaddrinfo: %s", + dprintf(LOG_ERR, FNAME, "Multicast1 getaddrinfo: %s", gai_strerror(error)); exit(1); } - memset(&mreq6, 0, sizeof(mreq6)); - mreq6.ipv6mr_interface = ifidx; - memcpy(&mreq6.ipv6mr_multiaddr, - &((struct sockaddr_in6 *)res2->ai_addr)->sin6_addr, - sizeof(mreq6.ipv6mr_multiaddr)); - if (setsockopt(insock, IPPROTO_IPV6, IPV6_JOIN_GROUP, - &mreq6, sizeof(mreq6))) { - dprintf(LOG_ERR, FNAME, - "setsockopt(insock, IPV6_JOIN_GROUP): %s", - strerror(errno)); - exit(1); + /* join multicast on all server interfaces */ + for (i = 0; i < argc; i++) { + memset(&mreq6, 0, sizeof(mreq6)); + mreq6.ipv6mr_interface = if_nametoindex(argv[i]); + dprintf(LOG_DEBUG, FNAME, "joining interface %s", argv[i]); + memcpy(&mreq6.ipv6mr_multiaddr, + &((struct sockaddr_in6 *)res2->ai_addr)->sin6_addr, + sizeof(mreq6.ipv6mr_multiaddr)); + if (setsockopt(insock, IPPROTO_IPV6, IPV6_JOIN_GROUP, + &mreq6, sizeof(mreq6))) { + dprintf(LOG_ERR, FNAME, + "setsockopt(insock, IPV6_JOIN_GROUP): %s", + strerror(errno)); + exit(1); + } } freeaddrinfo(res2); @@ -477,28 +484,33 @@ error = getaddrinfo(DH6ADDR_ALLSERVER, DH6PORT_UPSTREAM, &hints, &res2); if (error) { - dprintf(LOG_ERR, FNAME, "getaddrinfo: %s", + dprintf(LOG_ERR, FNAME, "Multicast2 getaddrinfo: %s", gai_strerror(error)); exit(1); } - memset(&mreq6, 0, sizeof(mreq6)); - mreq6.ipv6mr_interface = ifidx; - memcpy(&mreq6.ipv6mr_multiaddr, - &((struct sockaddr_in6 *)res2->ai_addr)->sin6_addr, - sizeof(mreq6.ipv6mr_multiaddr)); - if (setsockopt(insock, IPPROTO_IPV6, IPV6_JOIN_GROUP, - &mreq6, sizeof(mreq6))) { - dprintf(LOG_ERR, FNAME, - "setsockopt(insock, IPV6_JOIN_GROUP): %s", + /* join multicast on all server interfaces */ + for (i = 0; i < argc; i++) { + memset(&mreq6, 0, sizeof(mreq6)); + mreq6.ipv6mr_interface = if_nametoindex(argv[i]); + dprintf(LOG_DEBUG, FNAME, "joining interface %s again", argv[i]); + ifinit(argv[i]); + memcpy(&mreq6.ipv6mr_multiaddr, + &((struct sockaddr_in6 *)res2->ai_addr)->sin6_addr, + sizeof(mreq6.ipv6mr_multiaddr)); + if (setsockopt(insock, IPPROTO_IPV6, IPV6_JOIN_GROUP, + &mreq6, sizeof(mreq6))) { + dprintf(LOG_ERR, FNAME, + "setsockopt(insock, IPV6_JOIN_GROUP): %s", strerror(errno)); - exit(1); + exit(1); + } } freeaddrinfo(res2); hints.ai_flags = 0; - error = getaddrinfo(NULL, DH6PORT_DOWNSTREAM, &hints, &res); + error = getaddrinfo(nodeaddr, DH6PORT_DOWNSTREAM, &hints, &res); if (error) { - dprintf(LOG_ERR, FNAME, "getaddrinfo: %s", + dprintf(LOG_ERR, FNAME, "Downlink getaddrinfo: %s", gai_strerror(error)); exit(1); } @@ -508,14 +520,6 @@ strerror(errno)); exit(1); } - /* set outgoing interface of multicast packets for DHCP reconfig */ - if (setsockopt(outsock, IPPROTO_IPV6, IPV6_MULTICAST_IF, - &ifidx, sizeof(ifidx)) < 0) { - dprintf(LOG_ERR, FNAME, - "setsockopt(outsock, IPV6_MULTICAST_IF): %s", - strerror(errno)); - exit(1); - } #ifndef __linux__ /* make the socket write-only */ if (shutdown(outsock, 0)) { @@ -532,7 +536,7 @@ hints.ai_protocol = IPPROTO_UDP; error = getaddrinfo("::", DH6PORT_DOWNSTREAM, &hints, &res); if (error) { - dprintf(LOG_ERR, FNAME, "getaddrinfo: %s", + dprintf(LOG_ERR, FNAME, "Sdownstream getaddrinfo: %s", gai_strerror(error)); exit(1); } @@ -547,7 +551,7 @@ hints.ai_protocol = IPPROTO_UDP; error = getaddrinfo("::", DH6PORT_UPSTREAM, &hints, &res); if (error) { - dprintf(LOG_ERR, FNAME, "getaddrinfo: %s", + dprintf(LOG_ERR, FNAME, "Supstream getaddrinfo: %s", gai_strerror(error)); exit(1); } @@ -853,6 +857,9 @@ struct dhcp6opt *optend; struct relayinfolist relayinfohead; struct relayinfo *relayinfo; + char* ichar = NULL; + char* ichar2 = NULL; + int ifindex; TAILQ_INIT(&relayinfohead); @@ -891,13 +898,23 @@ * interface, when a DHCPv6 relay agent is running on that interface. * This check prevents such reception. */ - if (pi->ipi6_ifindex != ifidx) - return; + ifindex = pi->ipi6_ifindex; if ((ifp = find_ifconfbyid((unsigned int)pi->ipi6_ifindex)) == NULL) { dprintf(LOG_INFO, FNAME, "unexpected interface (%d)", (unsigned int)pi->ipi6_ifindex); return; } + + /* set outgoing interface of multicast packets for DHCP replies + * to the same one they came in at + */ + if (setsockopt(outsock, IPPROTO_IPV6, IPV6_MULTICAST_IF, + &ifindex, sizeof(ifindex)) < 0) { + dprintf(LOG_ERR, FNAME, + "setsockopt(outsock, IPV6_MULTICAST_IF): %s", + strerror(errno)); + exit(1); + } dh6 = (struct dhcp6 *)rdatabuf; @@ -909,7 +926,25 @@ dprintf(LOG_DEBUG, FNAME, "received %s from %s", dhcp6msgstr(dh6->dh6_msgtype), addr2str((struct sockaddr *)&from)); - + + ichar = index(addr2str((struct sockaddr *)&from),'%'); + if (ichar != NULL) { + ichar++; + ichar2=malloc(strlen(conffile) + strlen(ichar) + 4); + if (ichar2 != NULL) { + + strcpy(ichar2,conffile); + *(ichar2+strlen(conffile)) = '.'; + strcpy(ichar2+strlen(conffile)+1,ichar); + dprintf(LOG_DEBUG, FNAME, "will rehash on conffile %s", ichar2); + if (cfparse(ichar2) != 0) { + dprintf(LOG_WARNING, FNAME, + "failed to swapin configuration file"); + return; + } + free(ichar2); + } + } /* * A server MUST discard any Solicit, Confirm, Rebind or * Information-request messages it receives with a unicast