static int urandom_fd = -1;
+static void sighandler(_unused int signal)
+{
+ uloop_end();
+}
+
+
int main()
{
openlog("odhcpd", LOG_PERROR | LOG_PID, LOG_DAEMON);
+ setlogmask(LOG_UPTO(LOG_WARNING));
uloop_init();
if (getuid() != 0) {
return 4;
signal(SIGUSR1, SIG_IGN);
+ signal(SIGINT, sighandler);
+ signal(SIGTERM, sighandler);
if (init_router())
return 4;
// Read IPv6 MTU for interface
-int odhcpd_get_interface_mtu(const char *ifname)
+int odhcpd_get_interface_config(const char *ifname, const char *what)
{
char buf[64];
- const char *sysctl_pattern = "/proc/sys/net/ipv6/conf/%s/mtu";
- snprintf(buf, sizeof(buf), sysctl_pattern, ifname);
+ const char *sysctl_pattern = "/proc/sys/net/ipv6/conf/%s/%s";
+ snprintf(buf, sizeof(buf), sysctl_pattern, ifname, what);
int fd = open(buf, O_RDONLY);
ssize_t len = read(fd, buf, sizeof(buf) - 1);
if (len < 0)
return -1;
-
buf[len] = 0;
return atoi(buf);
-
}
{
// Construct headers
uint8_t cmsg_buf[CMSG_SPACE(sizeof(struct in6_pktinfo))] = {0};
- struct msghdr msg = {(void*)dest, sizeof(*dest), iov, iov_len,
- cmsg_buf, sizeof(cmsg_buf), 0};
+ struct msghdr msg = {
+ .msg_name = (void *) dest,
+ .msg_namelen = sizeof(*dest),
+ .msg_iov = iov,
+ .msg_iovlen = iov_len,
+ .msg_control = cmsg_buf,
+ .msg_controllen = sizeof(cmsg_buf),
+ .msg_flags = 0
+ };
// Set control data (define destination interface)
struct cmsghdr *chdr = CMSG_FIRSTHDR(&msg);
|| IN6_IS_ADDR_MC_LINKLOCAL(&dest->sin6_addr))
dest->sin6_scope_id = iface->ifindex;
- // IPV6_PKTINFO doesn't really work for IPv6-raw sockets (bug?)
- if (dest->sin6_port == 0) {
- msg.msg_control = NULL;
- msg.msg_controllen = 0;
- }
-
char ipbuf[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &dest->sin6_addr, ipbuf, sizeof(ipbuf));
ssize_t sent = sendmsg(socket, &msg, MSG_DONTWAIT);
if (sent < 0)
- syslog(LOG_WARNING, "Failed to send to %s%%%s (%s)",
+ syslog(LOG_NOTICE, "Failed to send to %s%%%s (%s)",
ipbuf, iface->ifname, strerror(errno));
else
- syslog(LOG_NOTICE, "Sent %li bytes to %s%%%s",
+ syslog(LOG_DEBUG, "Sent %li bytes to %s%%%s",
(long)sent, ipbuf, iface->ifname);
return sent;
}
struct ifaddrmsg *ifa = NLMSG_DATA(nhm);
if (ifa->ifa_scope != RT_SCOPE_UNIVERSE ||
- ifa->ifa_index != (unsigned)ifindex)
+ (ifindex && ifa->ifa_index != (unsigned)ifindex))
continue;
struct rtattr *rta = (struct rtattr*)&ifa[1];
if (ifa->ifa_flags & IFA_F_DEPRECATED)
addrs[ret].preferred = 0;
- addrs[ret].has_class = false;
- addrs[ret].class = 0;
-#ifdef WITH_UBUS
- struct interface *iface = odhcpd_get_interface_by_index(ifindex);
- if (iface) {
- addrs[ret].has_class = true;
- addrs[ret].class = ubus_get_class(iface->ifname, &addrs[ret].addr);
- }
-#endif
++ret;
}
return ret;
}
+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};
+ socklen_t alen = sizeof(addr);
+ int sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
+
+ if (!connect(sock, (struct sockaddr*)&addr, sizeof(addr)) &&
+ !getsockname(sock, (struct sockaddr*)&addr, &alen)) {
+ *lladdr = addr.sin6_addr;
+ status = 0;
+ }
+
+ close(sock);
+ return status;
+}
+
+void odhcpd_setup_route(const struct in6_addr *addr, int prefixlen,
+ const struct interface *iface, const struct in6_addr *gw,
+ int metric, bool add)
+{
+ struct req {
+ struct nlmsghdr nh;
+ struct rtmsg rtm;
+ struct rtattr rta_dst;
+ struct in6_addr dst_addr;
+ struct rtattr rta_oif;
+ uint32_t ifindex;
+ struct rtattr rta_table;
+ uint32_t table;
+ struct rtattr rta_prio;
+ uint32_t prio;
+ struct rtattr rta_gw;
+ struct in6_addr gw;
+ } req = {
+ {sizeof(req), 0, NLM_F_REQUEST, ++rtnl_seq, 0},
+ {AF_INET6, prefixlen, 0, 0, 0, 0, 0, 0, 0},
+ {sizeof(struct rtattr) + sizeof(struct in6_addr), RTA_DST},
+ *addr,
+ {sizeof(struct rtattr) + sizeof(uint32_t), RTA_OIF},
+ iface->ifindex,
+ {sizeof(struct rtattr) + sizeof(uint32_t), RTA_TABLE},
+ RT_TABLE_MAIN,
+ {sizeof(struct rtattr) + sizeof(uint32_t), RTA_PRIORITY},
+ metric,
+ {sizeof(struct rtattr) + sizeof(struct in6_addr), RTA_GATEWAY},
+ IN6ADDR_ANY_INIT,
+ };
+
+ if (gw)
+ req.gw = *gw;
+
+ if (add) {
+ req.nh.nlmsg_type = RTM_NEWROUTE;
+ req.nh.nlmsg_flags |= (NLM_F_CREATE | NLM_F_REPLACE);
+ req.rtm.rtm_protocol = RTPROT_STATIC;
+ req.rtm.rtm_scope = (gw) ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK;
+ req.rtm.rtm_type = RTN_UNICAST;
+ } else {
+ req.nh.nlmsg_type = RTM_DELROUTE;
+ req.rtm.rtm_scope = RT_SCOPE_NOWHERE;
+ }
+
+ req.nh.nlmsg_len = (gw) ? sizeof(req) : offsetof(struct req, rta_gw);
+ send(rtnl_socket, &req, req.nh.nlmsg_len, MSG_DONTWAIT);
+}
struct interface* odhcpd_get_interface_by_index(int ifindex)
{
while (true) {
struct iovec iov = {data_buf, sizeof(data_buf)};
- struct msghdr msg = {&addr, sizeof(addr), &iov, 1,
- cmsg_buf, sizeof(cmsg_buf), 0};
+ struct msghdr msg = {
+ .msg_name = (void *) &addr,
+ .msg_namelen = sizeof(addr),
+ .msg_iov = &iov,
+ .msg_iovlen = 1,
+ .msg_control = cmsg_buf,
+ .msg_controllen = sizeof(cmsg_buf),
+ .msg_flags = 0
+ };
ssize_t len = recvmsg(u->fd, &msg, MSG_DONTWAIT);
if (len < 0) {
// Extract destination interface
int destiface = 0;
int *hlim = NULL;
+ void *dest = NULL;
struct in6_pktinfo *pktinfo;
struct in_pktinfo *pkt4info;
- for (struct cmsghdr *ch = CMSG_FIRSTHDR(&msg); ch != NULL &&
- destiface == 0; ch = CMSG_NXTHDR(&msg, ch)) {
+ for (struct cmsghdr *ch = CMSG_FIRSTHDR(&msg); ch != NULL; ch = CMSG_NXTHDR(&msg, ch)) {
if (ch->cmsg_level == IPPROTO_IPV6 &&
ch->cmsg_type == IPV6_PKTINFO) {
pktinfo = (struct in6_pktinfo*)CMSG_DATA(ch);
destiface = pktinfo->ipi6_ifindex;
+ dest = &pktinfo->ipi6_addr;
} else if (ch->cmsg_level == IPPROTO_IP &&
ch->cmsg_type == IP_PKTINFO) {
pkt4info = (struct in_pktinfo*)CMSG_DATA(ch);
destiface = pkt4info->ipi_ifindex;
+ dest = &pkt4info->ipi_addr;
} else if (ch->cmsg_level == IPPROTO_IPV6 &&
ch->cmsg_type == IPV6_HOPLIMIT) {
hlim = (int*)CMSG_DATA(ch);
else if (addr.in.sin_family == AF_INET)
inet_ntop(AF_INET, &addr.in.sin_addr, ipbuf, sizeof(ipbuf));
- syslog(LOG_NOTICE, "--");
- syslog(LOG_NOTICE, "Received %li Bytes from %s%%%s", (long)len,
+ syslog(LOG_DEBUG, "--");
+ syslog(LOG_DEBUG, "Received %li Bytes from %s%%%s", (long)len,
ipbuf, (iface) ? iface->ifname : "netlink");
- e->handle_dgram(&addr, data_buf, len, iface);
+ e->handle_dgram(&addr, data_buf, len, iface, dest);
}
}
return uloop_fd_add(&event->uloop, ULOOP_READ);
}
-void odhcpd_urandom(void *data, size_t len)
+void odhcpd_process(struct odhcpd_event *event)
{
- read(urandom_fd, data, len);
+ odhcpd_receive_packets(&event->uloop, 0);
+}
+
+int odhcpd_urandom(void *data, size_t len)
+{
+ return read(urandom_fd, data, len);
}
}
*dst = 0;
}
+
+
+int odhcpd_bmemcmp(const void *av, const void *bv, size_t bits)
+{
+ const uint8_t *a = av, *b = bv;
+ size_t bytes = bits / 8;
+ bits %= 8;
+
+ int res = memcmp(a, b, bytes);
+ if (res == 0 && bits > 0)
+ res = (a[bytes] >> (8 - bits)) - (b[bytes] >> (8 - bits));
+
+ return res;
+}
+
+
+void odhcpd_bmemcpy(void *av, const void *bv, size_t bits)
+{
+ uint8_t *a = av;
+ const uint8_t *b = bv;
+
+ size_t bytes = bits / 8;
+ bits %= 8;
+ memcpy(a, b, bytes);
+
+ if (bits > 0) {
+ uint8_t mask = (1 << (8 - bits)) - 1;
+ a[bytes] = (a[bytes] & mask) | ((~mask) & b[bytes]);
+ }
+}