X-Git-Url: http://git.archive.openwrt.org/?p=project%2Fodhcpd.git;a=blobdiff_plain;f=src%2Fdhcpv4.c;h=3002c1e1721f63bf17e1a6b37cdcdebd63bf8b71;hp=166582e94ebe2fe971c97c457b0f7ad2a7a1a61b;hb=d834ae3ca59cf75cd7f26a5201a7223eaa468fbb;hpb=cf29925b29a4e4e38ab88573f12ec075eacb3d22 diff --git a/src/dhcpv4.c b/src/dhcpv4.c index 166582e..3002c1e 100644 --- a/src/dhcpv4.c +++ b/src/dhcpv4.c @@ -71,6 +71,8 @@ int dhcpv4_init(void) int dhcpv4_setup_interface(struct interface *iface, bool enable) { + int ret = 0; + if (iface->dhcpv4_event.uloop.fd > 0) { uloop_fd_delete(&iface->dhcpv4_event.uloop); close(iface->dhcpv4_event.uloop.fd); @@ -78,57 +80,97 @@ int dhcpv4_setup_interface(struct interface *iface, bool enable) } if (iface->dhcpv4 && enable) { + struct sockaddr_in bind_addr = {AF_INET, htons(DHCPV4_SERVER_PORT), + {INADDR_ANY}, {0}}; + int val = 1; + if (!iface->dhcpv4_assignments.next) INIT_LIST_HEAD(&iface->dhcpv4_assignments); if (!iface->dhcpv4_fr_ips.next) INIT_LIST_HEAD(&iface->dhcpv4_fr_ips); - int sock = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP); - if (sock < 0) { - syslog(LOG_ERR, "Failed to create DHCPv4 server socket: %s", - strerror(errno)); - return -1; + iface->dhcpv4_event.uloop.fd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP); + if (iface->dhcpv4_event.uloop.fd < 0) { + syslog(LOG_ERR, "socket(AF_INET): %m"); + ret = -1; + goto out; } /* Basic IPv4 configuration */ - int val = 1; - setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); - setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val)); - setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &val, sizeof(val)); + if (setsockopt(iface->dhcpv4_event.uloop.fd, SOL_SOCKET, SO_REUSEADDR, + &val, sizeof(val)) < 0) { + syslog(LOG_ERR, "setsockopt(SO_REUSEADDR): %m"); + ret = -1; + goto out; + } + + if (setsockopt(iface->dhcpv4_event.uloop.fd, SOL_SOCKET, SO_BROADCAST, + &val, sizeof(val)) < 0) { + syslog(LOG_ERR, "setsockopt(SO_BROADCAST): %m"); + ret = -1; + goto out; + } + + if (setsockopt(iface->dhcpv4_event.uloop.fd, IPPROTO_IP, IP_PKTINFO, + &val, sizeof(val)) < 0) { + syslog(LOG_ERR, "setsockopt(IP_PKTINFO): %m"); + ret = -1; + goto out; + } val = IPTOS_PREC_INTERNETCONTROL; - setsockopt(sock, IPPROTO_IP, IP_TOS, &val, sizeof(val)); + if (setsockopt(iface->dhcpv4_event.uloop.fd, IPPROTO_IP, IP_TOS, + &val, sizeof(val)) < 0) { + syslog(LOG_ERR, "setsockopt(IP_TOS): %m"); + ret = -1; + goto out; + } val = IP_PMTUDISC_DONT; - setsockopt(sock, IPPROTO_IP, IP_MTU_DISCOVER, &val, sizeof(val)); + if (setsockopt(iface->dhcpv4_event.uloop.fd, IPPROTO_IP, IP_MTU_DISCOVER, + &val, sizeof(val)) < 0) { + syslog(LOG_ERR, "setsockopt(IP_MTU_DISCOVER): %m"); + ret = -1; + goto out; + } - setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, - iface->ifname, strlen(iface->ifname)); + if (setsockopt(iface->dhcpv4_event.uloop.fd, SOL_SOCKET, SO_BINDTODEVICE, + iface->ifname, strlen(iface->ifname)) < 0) { + syslog(LOG_ERR, "setsockopt(SO_BINDTODEVICE): %m"); + ret = -1; + goto out; + } - struct sockaddr_in bind_addr = {AF_INET, htons(DHCPV4_SERVER_PORT), - {INADDR_ANY}, {0}}; + if (bind(iface->dhcpv4_event.uloop.fd, (struct sockaddr*)&bind_addr, + sizeof(bind_addr)) < 0) { + syslog(LOG_ERR, "bind(): %m"); + ret = -1; + goto out; + } - if (bind(sock, (struct sockaddr*)&bind_addr, sizeof(bind_addr))) { - syslog(LOG_ERR, "Failed to open DHCPv4 server socket: %s", - strerror(errno)); - return -1; + if (setup_dhcpv4_addresses(iface) < 0) { + ret = -1; + goto out; } - iface->dhcpv4_event.uloop.fd = sock; iface->dhcpv4_event.handle_dgram = handle_dhcpv4; odhcpd_register(&iface->dhcpv4_event); - if (setup_dhcpv4_addresses(iface) < 0) - return -1; - update_static_assignments(iface); } else if (iface->dhcpv4_assignments.next) { while (!list_empty(&iface->dhcpv4_assignments)) free_dhcpv4_assignment(list_first_entry(&iface->dhcpv4_assignments, struct dhcpv4_assignment, head)); } - return 0; + +out: + if (ret < 0 && iface->dhcpv4_event.uloop.fd > 0) { + close(iface->dhcpv4_event.uloop.fd); + iface->dhcpv4_event.uloop.fd = -1; + } + + return ret; } @@ -452,7 +494,9 @@ static void dhcpv4_put(struct dhcpv4_message *msg, uint8_t **cookie, uint8_t type, uint8_t len, const void *data) { uint8_t *c = *cookie; - if (*cookie + 2 + len > (uint8_t*)&msg[1]) + uint8_t *end = (uint8_t *)msg + sizeof(*msg); + + if (*cookie + 2 + len > end) return; *c++ = type; @@ -723,6 +767,11 @@ static void handle_dhcpv4(void *addr, void *data, size_t len, req->chaddr[0],req->chaddr[1],req->chaddr[2], req->chaddr[3],req->chaddr[4],req->chaddr[5]); +#ifdef WITH_UBUS + if (reqmsg == DHCPV4_MSG_RELEASE) + ubus_bcast_dhcp_event("dhcp.release", req->chaddr, req->hlen, + &req->ciaddr, hostname, iface->ifname); +#endif if (reqmsg == DHCPV4_MSG_DECLINE || reqmsg == DHCPV4_MSG_RELEASE) return; @@ -776,8 +825,10 @@ static void handle_dhcpv4(void *addr, void *data, size_t len, } } - struct ifreq ifr = {.ifr_name = ""}; - strncpy(ifr.ifr_name, iface->ifname, sizeof(ifr.ifr_name)); + struct ifreq ifr; + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, iface->ifname, sizeof(ifr.ifr_name) - 1); if (!ioctl(sock, SIOCGIFMTU, &ifr)) { uint16_t mtu = htons(ifr.ifr_mtu); @@ -872,6 +923,12 @@ static void handle_dhcpv4(void *addr, void *data, size_t len, sendto(sock, &reply, sizeof(reply), MSG_DONTWAIT, (struct sockaddr*)&dest, sizeof(dest)); + +#ifdef WITH_UBUS + if (msg == DHCPV4_MSG_ACK) + ubus_bcast_dhcp_event("dhcp.ack", req->chaddr, req->hlen, &reply.yiaddr, + hostname, iface->ifname); +#endif } static bool dhcpv4_assign(struct interface *iface,