#include <libubox/uloop.h>
#include "odhcpd.h"
-
-
-static int ioctl_sock;
+static int ioctl_sock = -1;
static int urandom_fd = -1;
static void sighandler(_unused int signal)
uloop_end();
}
-
static void print_usage(const char *app)
{
printf(
);
}
+static bool ipv6_enabled(void)
+{
+ int fd = socket(AF_INET6, SOCK_DGRAM, 0);
+
+ if (fd < 0)
+ return false;
+
+ close(fd);
+
+ return true;
+}
int main(int argc, char **argv)
{
ioctl_sock = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+ if (ioctl_sock < 0)
+ return 4;
+
if ((urandom_fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC)) < 0)
return 4;
if (netlink_init())
return 4;
- if (router_init())
- return 4;
+ if (ipv6_enabled()) {
+ if (router_init())
+ return 4;
- if (dhcpv6_init())
- return 4;
+ if (dhcpv6_init())
+ return 4;
- if (ndp_init())
+ if (ndp_init())
+ return 4;
+ }
+#ifndef DHCPV4_SUPPORT
+ else
return 4;
-
-#ifdef DHCPV4_SUPPORT
+#else
if (dhcpv4_init())
return 4;
#endif
}
-// Read IPv6 MTU for interface
+/* Read IPv6 MTU for interface */
int odhcpd_get_interface_config(const char *ifname, const char *what)
{
char buf[64];
snprintf(buf, sizeof(buf), sysctl_pattern, ifname, what);
int fd = open(buf, O_RDONLY);
+ if (fd < 0)
+ return -1;
+
ssize_t len = read(fd, buf, sizeof(buf) - 1);
close(fd);
}
-// Read IPv6 MAC for interface
+/* Read IPv6 MAC for interface */
int odhcpd_get_mac(const struct interface *iface, uint8_t mac[6])
{
struct ifreq ifr;
}
-// Forwards a packet on a specific interface
+/* Forwards a packet on a specific interface */
ssize_t odhcpd_send(int socket, struct sockaddr_in6 *dest,
struct iovec *iov, size_t iov_len,
const struct interface *iface)
{
- // Construct headers
+ /* Construct headers */
uint8_t cmsg_buf[CMSG_SPACE(sizeof(struct in6_pktinfo))] = {0};
struct msghdr msg = {
.msg_name = (void *) dest,
.msg_flags = 0
};
- // Set control data (define destination interface)
+ /* Set control data (define destination interface) */
struct cmsghdr *chdr = CMSG_FIRSTHDR(&msg);
chdr->cmsg_level = IPPROTO_IPV6;
chdr->cmsg_type = IPV6_PKTINFO;
struct in6_pktinfo *pktinfo = (struct in6_pktinfo*)CMSG_DATA(chdr);
pktinfo->ipi6_ifindex = iface->ifindex;
- // Also set scope ID if link-local
+ /* Also set scope ID if link-local */
if (IN6_IS_ADDR_LINKLOCAL(&dest->sin6_addr)
|| IN6_IS_ADDR_MC_LINKLOCAL(&dest->sin6_addr))
dest->sin6_scope_id = iface->ifindex;
ssize_t sent = sendmsg(socket, &msg, MSG_DONTWAIT);
if (sent < 0)
- syslog(LOG_NOTICE, "Failed to send to %s%%%s (%m)",
- ipbuf, iface->ifname);
+ syslog(LOG_ERR, "Failed to send to %s%%%s@%s (%m)",
+ ipbuf, iface->name, iface->ifname);
else
- syslog(LOG_DEBUG, "Sent %li bytes to %s%%%s",
- (long)sent, ipbuf, iface->ifname);
+ syslog(LOG_DEBUG, "Sent %zd bytes to %s%%%s@%s",
+ sent, ipbuf, iface->name, iface->ifname);
return sent;
}
static int odhcpd_get_linklocal_interface_address(int ifindex, struct in6_addr *lladdr)
{
- int status = -1;
- struct sockaddr_in6 addr = {AF_INET6, 0, 0, ALL_IPV6_ROUTERS, ifindex};
+ int ret = -1;
+ struct sockaddr_in6 addr;
socklen_t alen = sizeof(addr);
int sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
+ if (sock < 0)
+ return -1;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin6_family = AF_INET6;
+ inet_pton(AF_INET6, ALL_IPV6_ROUTERS, &addr.sin6_addr);
+ addr.sin6_scope_id = ifindex;
+
if (!connect(sock, (struct sockaddr*)&addr, sizeof(addr)) &&
!getsockname(sock, (struct sockaddr*)&addr, &alen)) {
*lladdr = addr.sin6_addr;
- status = 0;
+ ret = 0;
}
close(sock);
-
- return status;
+ return ret;
}
/*
struct interface* odhcpd_get_interface_by_index(int ifindex)
{
struct interface *iface;
- list_for_each_entry(iface, &interfaces, head)
- if (iface->ifindex == ifindex)
- return iface;
- return NULL;
-}
-
-
-struct interface* odhcpd_get_interface_by_name(const char *name)
-{
- struct interface *iface;
- list_for_each_entry(iface, &interfaces, head)
- if (!strcmp(iface->ifname, name))
- return iface;
-
- return NULL;
-}
-
-
-struct interface* odhcpd_get_master_interface(void)
-{
- struct interface *iface;
- list_for_each_entry(iface, &interfaces, head)
- if (iface->master)
+ avl_for_each_element(&interfaces, iface, avl) {
+ if (iface->ifindex == ifindex)
return iface;
+ }
return NULL;
}
-
-// Convenience function to receive and do basic validation of packets
+/* Convenience function to receive and do basic validation of packets */
static void odhcpd_receive_packets(struct uloop_fd *u, _unused unsigned int events)
{
struct odhcpd_event *e = container_of(u, struct odhcpd_event, uloop);
if (u->error) {
int ret = -1;
socklen_t ret_len = sizeof(ret);
- getsockopt(u->fd, SOL_SOCKET, SO_ERROR, &ret, &ret_len);
+
u->error = false;
- if (e->handle_error)
+ if (e->handle_error && getsockopt(u->fd, SOL_SOCKET, SO_ERROR, &ret, &ret_len) == 0)
e->handle_error(e, ret);
}
}
- // Extract destination interface
+ /* Extract destination interface */
int destiface = 0;
int *hlim = NULL;
void *dest = NULL;
}
}
- // Check hoplimit if received
+ /* Check hoplimit if received */
if (hlim && *hlim != 255)
continue;
- // Detect interface for packet sockets
+ /* Detect interface for packet sockets */
if (addr.ll.sll_family == AF_PACKET)
destiface = addr.ll.sll_ifindex;
else if (addr.in.sin_family == AF_INET)
inet_ntop(AF_INET, &addr.in.sin_addr, ipbuf, sizeof(ipbuf));
- // From netlink
+ /* From netlink */
if (addr.nl.nl_family == AF_NETLINK) {
- syslog(LOG_DEBUG, "Received %li Bytes from %s%%%s", (long)len,
- ipbuf, "netlink");
+ syslog(LOG_DEBUG, "Received %zd Bytes from %s%%netlink", len,
+ ipbuf);
e->handle_dgram(&addr, data_buf, len, NULL, dest);
return;
} else if (destiface != 0) {
struct interface *iface;
- list_for_each_entry(iface, &interfaces, head) {
+
+ avl_for_each_element(&interfaces, iface, avl) {
if (iface->ifindex != destiface)
continue;
- syslog(LOG_DEBUG, "Received %li Bytes from %s%%%s", (long)len,
- ipbuf, iface->ifname);
+ syslog(LOG_DEBUG, "Received %zd Bytes from %s%%%s@%s", len,
+ ipbuf, iface->name, iface->ifname);
e->handle_dgram(&addr, data_buf, len, iface, dest);
}
}
}
-// Register events for the multiplexer
+/* Register events for the multiplexer */
int odhcpd_register(struct odhcpd_event *event)
{
event->uloop.cb = odhcpd_receive_packets;
time_t odhcpd_time(void)
{
struct timespec ts;
- syscall(SYS_clock_gettime, CLOCK_MONOTONIC, &ts);
+ clock_gettime(CLOCK_MONOTONIC, &ts);
return ts.tv_sec;
}
return true;
}
+
+bool odhcpd_valid_hostname(const char *name)
+{
+#define MAX_LABEL 63
+ const char *c, *label, *label_end;
+ int label_sz = 0;
+
+ for (c = name, label_sz = 0, label = name, label_end = name + strcspn(name, ".") - 1;
+ *c && label_sz <= MAX_LABEL; c++) {
+ if ((*c >= '0' && *c <= '9') ||
+ (*c >= 'A' && *c <= 'Z') ||
+ (*c >= 'a' && *c <= 'z')) {
+ label_sz++;
+ continue;
+ }
+
+ if ((*c == '_' || *c == '-') && c != label && c != label_end) {
+ label_sz++;
+ continue;
+ }
+
+ if (*c == '.') {
+ if (*(c + 1)) {
+ label = c + 1;
+ label_end = label + strcspn(label, ".") - 1;
+ label_sz = 0;
+ }
+ continue;
+ }
+
+ return false;
+ }
+
+ return (label_sz && label_sz <= MAX_LABEL ? true : false);
+}