On Thu, 10 Jul 2014 10:17:29 +0200 (CEST) YASUOKA Masahiko <yasu...@yasuoka.net> wrote: > On Wed, 9 Jul 2014 16:57:44 +0200 > Kenneth Westerback <kwesterb...@gmail.com> wrote: >> On 9 July 2014 16:23, YASUOKA Masahiko <yasu...@yasuoka.net> wrote: >>> Some users of npppd(8) want to use dhcpd(8) on tunneling interface to >>> provide additional routing entries and so on to VPN clients. So I'd >>> like to make the dhcpd work on the DLT_LOOP interfaces. >>> >>> comment or ok? >>> >>> Make dhcpd(8) work on the DLT_LOOP interfaces. > (snip) >> Unfortunately all this bpf stuff is black magic to me. Ditto DLT_LOOP. >> If it works I have no objection, but I'm not able to ok it. > > This reminded me that I had another way. > > This bpf magic was to use dhcpd(8) on tunneling interfaces. But on > tunnel interfaces, client's IP address must be configured before the > DHCP. Therefore > > - only DHCPINFORM is usable > - bpf is not required. a normal UDP socket can be used instead > > I added udp socket mode to dhcpd(8). This also makes dhcpd answer > DHCP inform on tunnel interfaces. I've tested this with the dhcp > inform diff and iPad already. > > How about this direction?
Let me update the diff Fixing the byte order of the server_port and small changes. Index: usr.sbin/dhcpd/Makefile =================================================================== RCS file: /disk/cvs/openbsd/src/usr.sbin/dhcpd/Makefile,v retrieving revision 1.4 diff -u -p -r1.4 Makefile --- usr.sbin/dhcpd/Makefile 7 May 2008 12:19:20 -0000 1.4 +++ usr.sbin/dhcpd/Makefile 10 Jul 2014 08:59:03 -0000 @@ -4,7 +4,8 @@ SRCS= bootp.c confpars.c db.c dhcp.c dhcpd.c bpf.c packet.c errwarn.c \ dispatch.c print.c memory.c options.c inet.c conflex.c parse.c \ - alloc.c tables.c tree.c hash.c convert.c icmp.c pfutils.c sync.c + alloc.c tables.c tree.c hash.c convert.c icmp.c pfutils.c sync.c \ + udpsock.c PROG= dhcpd MAN= dhcpd.8 dhcpd.conf.5 dhcpd.leases.5 dhcp-options.5 Index: usr.sbin/dhcpd/bootp.c =================================================================== RCS file: /disk/cvs/openbsd/src/usr.sbin/dhcpd/bootp.c,v retrieving revision 1.14 diff -u -p -r1.14 bootp.c --- usr.sbin/dhcpd/bootp.c 11 Jun 2014 16:45:15 -0000 1.14 +++ usr.sbin/dhcpd/bootp.c 10 Jul 2014 08:59:03 -0000 @@ -325,7 +325,7 @@ lose: to.sin_addr = raw.giaddr; to.sin_port = server_port; - (void) send_packet(packet->interface, &raw, + (void) packet->interface->send_packet(packet->interface, &raw, outgoing.packet_length, from, &to, packet->haddr); return; } @@ -345,6 +345,6 @@ lose: } errno = 0; - (void) send_packet(packet->interface, &raw, + (void) packet->interface->send_packet(packet->interface, &raw, outgoing.packet_length, from, &to, packet->haddr); } Index: usr.sbin/dhcpd/bpf.c =================================================================== RCS file: /disk/cvs/openbsd/src/usr.sbin/dhcpd/bpf.c,v retrieving revision 1.10 diff -u -p -r1.10 bpf.c --- usr.sbin/dhcpd/bpf.c 5 Apr 2013 19:31:36 -0000 1.10 +++ usr.sbin/dhcpd/bpf.c 10 Jul 2014 08:59:03 -0000 @@ -52,6 +52,9 @@ #define BPF_FORMAT "/dev/bpf%d" +ssize_t send_packet (struct interface_info *, struct dhcp_packet *, + size_t, struct in_addr, struct sockaddr_in *, struct hardware *); + /* * Called by get_interface_list for each interface that's discovered. * Opens a packet filter for each interface and adds it to the select @@ -81,6 +84,7 @@ if_register_bpf(struct interface_info *i error("Can't attach interface %s to bpf device %s: %m", info->name, filename); + info->send_packet = send_packet; return (sock); } Index: usr.sbin/dhcpd/dhcp.c =================================================================== RCS file: /disk/cvs/openbsd/src/usr.sbin/dhcpd/dhcp.c,v retrieving revision 1.36 diff -u -p -r1.36 dhcp.c --- usr.sbin/dhcpd/dhcp.c 5 Apr 2013 19:31:36 -0000 1.36 +++ usr.sbin/dhcpd/dhcp.c 10 Jul 2014 08:59:04 -0000 @@ -652,7 +652,7 @@ nak_lease(struct packet *packet, struct to.sin_addr = raw.giaddr; to.sin_port = server_port; - result = send_packet(packet->interface, &raw, + result = packet->interface->send_packet(packet->interface, &raw, outgoing.packet_length, from, &to, packet->haddr); if (result == -1) warning("send_fallback: %m"); @@ -663,7 +663,7 @@ nak_lease(struct packet *packet, struct } errno = 0; - result = send_packet(packet->interface, &raw, + result = packet->interface->send_packet(packet->interface, &raw, outgoing.packet_length, from, &to, NULL); } @@ -1327,7 +1327,7 @@ dhcp_reply(struct lease *lease) memcpy(&from, state->from.iabuf, sizeof from); - (void) send_packet(state->ip, &raw, + (void) state->ip->send_packet(state->ip, &raw, packet_length, from, &to, &state->haddr); free_lease_state(state, "dhcp_reply gateway"); @@ -1371,7 +1371,7 @@ dhcp_reply(struct lease *lease) memcpy(&from, state->from.iabuf, sizeof from); - (void) send_packet(state->ip, &raw, packet_length, + (void) state->ip->send_packet(state->ip, &raw, packet_length, from, &to, &state->haddr); free_lease_state(state, "dhcp_reply"); Index: usr.sbin/dhcpd/dhcpd.8 =================================================================== RCS file: /disk/cvs/openbsd/src/usr.sbin/dhcpd/dhcpd.8,v retrieving revision 1.22 diff -u -p -r1.22 dhcpd.8 --- usr.sbin/dhcpd/dhcpd.8 3 Jan 2014 16:21:58 -0000 1.22 +++ usr.sbin/dhcpd/dhcpd.8 10 Jul 2014 08:59:04 -0000 @@ -45,9 +45,10 @@ .Sh SYNOPSIS .Nm dhcpd .Bk -words -.Op Fl dfn +.Op Fl dfnu .Op Fl A Ar abandoned_ip_table .Op Fl C Ar changed_ip_table +.Op Fl b Ar bind_address .Op Fl c Ar config-file .Op Fl L Ar leased_ip_table .Op Fl l Ar lease-file @@ -149,7 +150,9 @@ This should be done on systems where .Nm is unable to identify non-broadcast interfaces, but should not be required on other systems. -If no interface names are specified on the command line, +If any interface name and +.Fl u +is not specified on the command line, .Nm will identify all network interfaces which are up, eliminating non-broadcast interfaces if possible, and listen for DHCP broadcasts on each interface. @@ -180,6 +183,23 @@ When the address is leased to a differen .Nm can remove the address from the overload table, thus allowing a well-behaved machine to reuse the address. +.It Fl b Ar bind_address +When +.Fl u +option is specified, +.Nm +will bind the limited broadcast address (255.255.255.255) for the UDP socket +by default. +The +.Fl b +option, followed by +.Ar bind_address +specifies the address +.Nm +should bind. +This option must be combined with +.Fl u +option. .It Fl c Ar config-file Use an alternate configuration file, .Ar config-file . @@ -239,6 +259,8 @@ for testing lease files in a non-product .It Fl n Only test configuration, do not run .Nm . +.It Fl u +Use an UDP socket instead of BPF for receiving and sending packets. .It Fl Y Ar synctarget Add target .Ar synctarget Index: usr.sbin/dhcpd/dhcpd.c =================================================================== RCS file: /disk/cvs/openbsd/src/usr.sbin/dhcpd/dhcpd.c,v retrieving revision 1.44 diff -u -p -r1.44 dhcpd.c --- usr.sbin/dhcpd/dhcpd.c 7 May 2014 13:20:47 -0000 1.44 +++ usr.sbin/dhcpd/dhcpd.c 10 Jul 2014 08:59:04 -0000 @@ -71,18 +71,19 @@ struct syslog_data sdata = SYSLOG_DATA_I int main(int argc, char *argv[]) { - int ch, cftest = 0, daemonize = 1, rdomain = -1; + int ch, cftest = 0, daemonize = 1, rdomain = -1, udpsockmode = 0; extern char *__progname; char *sync_iface = NULL; char *sync_baddr = NULL; u_short sync_port = 0; struct servent *ent; + struct in_addr udpaddr; /* Initially, log errors to stderr as well as to syslogd. */ openlog_r(__progname, LOG_PID | LOG_NDELAY, DHCPD_LOG_FACILITY, &sdata); opterr = 0; - while ((ch = getopt(argc, argv, "A:C:L:c:dfl:nY:y:")) != -1) + while ((ch = getopt(argc, argv, "A:C:L:b:c:dfl:nuY:y:")) != -1) switch (ch) { case 'Y': syncsend = 1; @@ -98,8 +99,10 @@ main(int argc, char *argv[]) sync_port = ntohs(ent->s_port); } + udpaddr.s_addr = htonl(INADDR_BROADCAST); + optreset = optind = opterr = 1; - while ((ch = getopt(argc, argv, "A:C:L:c:dfl:nY:y:")) != -1) + while ((ch = getopt(argc, argv, "A:C:L:b:c:dfl:nuY:y:")) != -1) switch (ch) { case 'A': abandoned_tab = optarg; @@ -110,6 +113,11 @@ main(int argc, char *argv[]) case 'L': leased_tab = optarg; break; + case 'b': + if (inet_aton(optarg, &udpaddr) != 1) + errx(1, "Cannot parse binding IP address: %s", + optarg); + break; case 'c': path_dhcpd_conf = optarg; break; @@ -128,6 +136,9 @@ main(int argc, char *argv[]) cftest = 1; log_perror = 1; break; + case 'u': + udpsockmode = 1; + break; case 'Y': if (sync_addhost(optarg, sync_port) != 0) sync_iface = optarg; @@ -169,12 +180,15 @@ main(int argc, char *argv[]) exit(0); db_startup(); - discover_interfaces(&rdomain); + if (!udpsockmode || argc > 0) + discover_interfaces(&rdomain); if (rdomain != -1) if (setrtable(rdomain) == -1) error("setrtable (%m)"); + if (udpsockmode) + udpsock_startup(udpaddr); icmp_startup(1, lease_pinged); if (syncsend || syncrecv) { @@ -232,11 +246,13 @@ usage(void) { extern char *__progname; - fprintf(stderr, "usage: %s [-dfn] [-A abandoned_ip_table]", __progname); + fprintf(stderr, "usage: %s [-dfnu] [-A abandoned_ip_table]", + __progname); fprintf(stderr, " [-C changed_ip_table]\n"); - fprintf(stderr, "\t[-c config-file] [-L leased_ip_table]"); - fprintf(stderr, " [-l lease-file] [-Y synctarget] [-y synclisten]\n"); - fprintf(stderr, "\t[if0 [... ifN]]\n"); + fprintf(stderr, "\t[-b bind_address] [-c config-file]"); + fprintf(stderr, " [-L leased_ip_table]\n"); + fprintf(stderr, "\t[-l lease-file] [-Y synctarget] [-y synclisten]"); + fprintf(stderr, " [if0 [... ifN]]\n"); exit(1); } Index: usr.sbin/dhcpd/dhcpd.h =================================================================== RCS file: /disk/cvs/openbsd/src/usr.sbin/dhcpd/dhcpd.h,v retrieving revision 1.50 diff -u -p -r1.50 dhcpd.h --- usr.sbin/dhcpd/dhcpd.h 7 May 2014 13:20:47 -0000 1.50 +++ usr.sbin/dhcpd/dhcpd.h 10 Jul 2014 08:59:04 -0000 @@ -424,6 +424,8 @@ struct interface_info { int errors; int dead; u_int16_t index; + ssize_t (*send_packet)(struct interface_info *, struct dhcp_packet *, + size_t, struct in_addr, struct sockaddr_in *, struct hardware *); }; struct hardware_link { @@ -616,8 +618,6 @@ char *print_hw_addr(int, int, unsigned c /* bpf.c */ int if_register_bpf(struct interface_info *); void if_register_send(struct interface_info *); -ssize_t send_packet(struct interface_info *, struct dhcp_packet *, size_t, - struct in_addr, struct sockaddr_in *, struct hardware *); void if_register_receive(struct interface_info *); ssize_t receive_packet(struct interface_info *, unsigned char *, size_t, struct sockaddr_in *, struct hardware *); @@ -697,3 +697,6 @@ size_t atomicio(ssize_t (*)(int, void *, #define vwrite (ssize_t (*)(int, void *, size_t))write void pfmsg(char, struct lease *); extern struct syslog_data sdata; + +/* udpsock.c */ +void udpsock_startup(struct in_addr); Index: usr.sbin/dhcpd/udpsock.c =================================================================== RCS file: usr.sbin/dhcpd/udpsock.c diff -N usr.sbin/dhcpd/udpsock.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ usr.sbin/dhcpd/udpsock.c 10 Jul 2014 08:59:04 -0000 @@ -0,0 +1,341 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2014 YASUOKA Masahiko <yasu...@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/uio.h> +#include <sys/ioctl.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <errno.h> +#include <stdint.h> +#include <string.h> + +#include "dhcpd.h" + +void udpsock_handler (struct protocol *); +ssize_t udpsock_send_packet(struct interface_info *, struct dhcp_packet *, + size_t, struct in_addr, struct sockaddr_in *, struct hardware *); + +struct udpsock { + int sock; +}; + +void +udpsock_startup(struct in_addr bindaddr) +{ + int sock, onoff; + struct sockaddr_in sin4; + struct udpsock *udpsock; + + if ((udpsock = calloc(1, sizeof(struct udpsock))) == NULL) + error("could not create udpsock: %s", strerror(errno)); + + memset(&sin4, 0, sizeof(sin4)); + if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) + error("creating a socket failed for udp: %s", strerror(errno)); + + onoff = 1; + if (setsockopt(sock, IPPROTO_IP, IP_RECVIF, &onoff, sizeof(onoff)) != 0) + error("setsocketopt IP_RECVIF failed for udp: %s", + strerror(errno)); + + sin4.sin_family = AF_INET; + sin4.sin_len = sizeof(sin4); + sin4.sin_addr = bindaddr; + sin4.sin_port = server_port; + + if (bind(sock, (struct sockaddr *)&sin4, sizeof(sin4)) != 0) + error("bind failed for udp: %s", strerror(errno)); + + add_protocol("udp", sock, udpsock_handler, (void *)(intptr_t)udpsock); + note("Listening on %s:%d/udp.", inet_ntoa(sin4.sin_addr), + ntohs(server_port)); + + udpsock->sock = sock; +} + +void +udpsock_handler(struct protocol *protocol) +{ + int sockio; + char cbuf[256], ifname[IF_NAMESIZE]; + ssize_t len; + struct udpsock *udpsock = protocol->local; + struct msghdr m; + struct cmsghdr *cm; + struct iovec iov[1]; + struct sockaddr_storage ss; + struct sockaddr_in *sin4; + struct sockaddr_dl *sdl = NULL; + struct interface_info iface; + struct iaddr from, addr; + unsigned char packetbuf[4095]; + struct dhcp_packet *packet = (struct dhcp_packet *)packetbuf; + struct hardware hw; + struct ifreq ifr; + struct subnet *subnet; + + memset(&hw, 0, sizeof(hw)); + + iov[0].iov_base = packetbuf; + iov[0].iov_len = sizeof(packetbuf); + memset(&m, 0, sizeof(m)); + m.msg_name = &ss; + m.msg_namelen = sizeof(ss); + m.msg_iov = iov; + m.msg_iovlen = nitems(iov); + m.msg_control = cbuf; + m.msg_controllen = sizeof(cbuf); + + memset(&iface, 0, sizeof(iface)); + if ((len = recvmsg(udpsock->sock, &m, 0)) < 0) { + warning("receiving a DHCP message failed: %s", strerror(errno)); + return; + } + if (ss.ss_family != AF_INET) { + warning("received DHCP message is not AF_INET"); + return; + } + sin4 = (struct sockaddr_in *)&ss; + for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&m); + m.msg_controllen != 0 && cm; + cm = (struct cmsghdr *)CMSG_NXTHDR(&m, cm)) { + if (cm->cmsg_level == IPPROTO_IP && + cm->cmsg_type == IP_RECVIF) + sdl = (struct sockaddr_dl *)CMSG_DATA(cm); + } + if (sdl == NULL) { + warning("could not get the received interface by IP_RECVIF"); + return; + } + if_indextoname(sdl->sdl_index, ifname); + + if ((sockio = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + warning("socket creation failed: %s", strerror(errno)); + return; + } + strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + if (ioctl(sockio, SIOCGIFADDR, &ifr, sizeof(ifr)) != 0) { + warning("Failed to get address for %s: %s", ifname, + strerror(errno)); + close(sockio); + return; + } + close(sockio); + + if (ifr.ifr_addr.sa_family != AF_INET) + return; + + iface.send_packet = udpsock_send_packet; + iface.wfdesc = udpsock->sock; + iface.ifp = 𝔦 + iface.index = sdl->sdl_index; + iface.primary_address = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr; + strlcpy(iface.name, ifname, sizeof(iface.name)); + + addr.len = 4; + memcpy(&addr.iabuf, &iface.primary_address, addr.len); + + if ((subnet = find_subnet(addr)) == NULL) + return; + iface.shared_network = subnet->shared_network ; + from.len = 4; + memcpy(&from.iabuf, &sin4->sin_addr, from.len); + do_packet(&iface, packet, len, sin4->sin_port, from, &hw); +} + +ssize_t +udpsock_send_packet(struct interface_info *interface, struct dhcp_packet *raw, + size_t len, struct in_addr from, struct sockaddr_in *to, + struct hardware *hto) +{ + return (sendto(interface->wfdesc, raw, len, 0, (struct sockaddr *)to, + sizeof(struct sockaddr_in))); +} +/* $OpenBSD$ */ + +/* + * Copyright (c) 2014 YASUOKA Masahiko <yasu...@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/uio.h> +#include <sys/ioctl.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <errno.h> +#include <stdint.h> +#include <string.h> + +#include "dhcpd.h" + +void udpsock_handler (struct protocol *); +ssize_t udpsock_send_packet(struct interface_info *, struct dhcp_packet *, + size_t, struct in_addr, struct sockaddr_in *, struct hardware *); + +struct udpsock { + int sock; +}; + +void +udpsock_startup(struct in_addr listenaddr) +{ + int sock, onoff; + struct sockaddr_in sin4; + struct udpsock *udpsock; + + if ((udpsock = calloc(1, sizeof(struct udpsock))) == NULL) + error("could not create udpsock: %s", strerror(errno)); + + memset(&sin4, 0, sizeof(sin4)); + if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) + error("creating a socket failed for udp: %s", strerror(errno)); + + onoff = 1; + if (setsockopt(sock, IPPROTO_IP, IP_RECVIF, &onoff, sizeof(onoff)) != 0) + error("setsocketopt IP_RECVIF failed for udp: %s", + strerror(errno)); + + sin4.sin_family = AF_INET; + sin4.sin_len = sizeof(sin4); + sin4.sin_addr = listenaddr; + sin4.sin_port = htons(server_port); + + if (bind(sock, (struct sockaddr *)&sin4, sizeof(sin4)) != 0) + error("bind failed for udp: %s", strerror(errno)); + + add_protocol("udp", sock, udpsock_handler, (void *)(intptr_t)udpsock); + note("Listening as UDP socket on %s.", inet_ntoa(sin4.sin_addr)); + + udpsock->sock = sock; +} + +void +udpsock_handler(struct protocol *protocol) +{ + int sockio; + char cbuf[256], ifname[IF_NAMESIZE]; + ssize_t len; + struct udpsock *udpsock = protocol->local; + struct msghdr m; + struct cmsghdr *cm; + struct iovec iov[1]; + struct sockaddr_storage ss; + struct sockaddr_in *sin4; + struct sockaddr_dl *sdl = NULL; + struct interface_info iface; + struct iaddr from, addr; + unsigned char packetbuf[4095]; + struct dhcp_packet *packet = (struct dhcp_packet *)packetbuf; + struct hardware hw; + struct ifreq ifr; + struct subnet *subnet; + + memset(&hw, 0, sizeof(hw)); + + iov[0].iov_base = packetbuf; + iov[0].iov_len = sizeof(packetbuf); + memset(&m, 0, sizeof(m)); + m.msg_name = &ss; + m.msg_namelen = sizeof(ss); + m.msg_iov = iov; + m.msg_iovlen = nitems(iov); + m.msg_control = cbuf; + m.msg_controllen = sizeof(cbuf); + + memset(&iface, 0, sizeof(iface)); + if ((len = recvmsg(udpsock->sock, &m, 0)) < 0) { + warning("receiving a DHCP message failed: %s", strerror(errno)); + return; + } + if (ss.ss_family != AF_INET) { + warning("received DHCP message is not AF_INET"); + return; + } + sin4 = (struct sockaddr_in *)&ss; + for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&m); + m.msg_controllen != 0 && cm; + cm = (struct cmsghdr *)CMSG_NXTHDR(&m, cm)) { + if (cm->cmsg_level == IPPROTO_IP && + cm->cmsg_type == IP_RECVIF) + sdl = (struct sockaddr_dl *)CMSG_DATA(cm); + } + if (sdl == NULL) { + warning("could not get the received interface by IP_RECVIF"); + return; + } + if_indextoname(sdl->sdl_index, ifname); + + if ((sockio = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + warning("socket creation failed: %s", strerror(errno)); + return; + } + strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + if (ioctl(sockio, SIOCGIFADDR, &ifr, sizeof(ifr)) != 0) { + warning("Failed to get address for %s: %s", ifname, + strerror(errno)); + close(sockio); + return; + } + close(sockio); + + if (ifr.ifr_addr.sa_family != AF_INET) + return; + + iface.send_packet = udpsock_send_packet; + iface.wfdesc = udpsock->sock; + iface.ifp = 𝔦 + iface.index = sdl->sdl_index; + iface.primary_address = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr; + strlcpy(iface.name, ifname, sizeof(iface.name)); + + addr.len = 4; + memcpy(&addr.iabuf, &iface.primary_address, addr.len); + + if ((subnet = find_subnet(addr)) == NULL) + return; + iface.shared_network = subnet->shared_network ; + from.len = 4; + memcpy(&from.iabuf, &sin4->sin_addr, from.len); + do_packet(&iface, packet, len, sin4->sin_port, from, &hw); +} + +ssize_t +udpsock_send_packet(struct interface_info *interface, struct dhcp_packet *raw, + size_t len, struct in_addr from, struct sockaddr_in *to, + struct hardware *hto) +{ + return (sendto(interface->wfdesc, raw, len, 0, (struct sockaddr *)to, + sizeof(struct sockaddr_in))); +}