memcpy(p, &tip, sizeof(tip));
p += sizeof(tip);
len = p - arp_buffer;
- retval = send_raw_packet(ifp, ETHERTYPE_ARP, arp_buffer, len);
+ retval = ipv4_sendrawpacket(ifp, ETHERTYPE_ARP, arp_buffer, len);
return retval;
}
state = D_STATE(ifp);
state->fail.s_addr = 0;
for(;;) {
- bytes = get_raw_packet(ifp, ETHERTYPE_ARP,
+ bytes = ipv4_getrawpacket(ifp, ETHERTYPE_ARP,
arp_buffer, sizeof(arp_buffer), NULL);
if (bytes == 0 || bytes == -1)
return;
if (state->new == NULL)
return;
if (state->arp_fd == -1) {
- open_socket(ifp, ETHERTYPE_ARP);
+ ipv4_opensocket(ifp, ETHERTYPE_ARP);
eloop_event_add(state->arp_fd, arp_packet, ifp);
}
if (++state->claims < ANNOUNCE_NUM)
addr.s_addr = state->addr.s_addr;
if (state->arp_fd == -1) {
- open_socket(ifp, ETHERTYPE_ARP);
+ ipv4_opensocket(ifp, ETHERTYPE_ARP);
eloop_event_add(state->arp_fd, arp_packet, ifp);
}
if (state->probes == 0) {
# include <linux/rtnetlink.h>
#endif
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#define __FAVOR_BSD /* Nasty glibc hack so we can use BSD semantics for UDP */
+#include <netinet/udp.h>
+#undef __FAVOR_BSD
+
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
+#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
NULL
};
+struct udp_dhcp_packet
+{
+ struct ip ip;
+ struct udphdr udp;
+ struct dhcp_message dhcp;
+};
+static const size_t udp_dhcp_len = sizeof(struct udp_dhcp_packet);
+
static int dhcp_open(struct interface *);
void
while (p < e) {
cidr = *p++;
if (cidr > 32) {
- free_routes(routes);
+ ipv4_freeroutes(routes);
errno = EINVAL;
return NULL;
}
addr.s_addr = dhcp->yiaddr ? dhcp->yiaddr : dhcp->ciaddr;
setvar(&ep, prefix, "ip_address", inet_ntoa(addr));
if (get_option_addr(&net, dhcp, DHO_SUBNETMASK) == -1) {
- net.s_addr = get_netmask(addr.s_addr);
+ net.s_addr = ipv4_getnetmask(addr.s_addr);
setvar(&ep, prefix, "subnet_mask", inet_ntoa(net));
}
snprintf(cidr, sizeof(cidr), "%d", inet_ntocidr(net));
else
lease->addr.s_addr = dhcp->ciaddr;
if (get_option_addr(&lease->net, dhcp, DHO_SUBNETMASK) == -1)
- lease->net.s_addr = get_netmask(lease->addr.s_addr);
+ lease->net.s_addr = ipv4_getnetmask(lease->addr.s_addr);
if (get_option_addr(&lease->brd, dhcp, DHO_BROADCAST) == -1)
lease->brd.s_addr = lease->addr.s_addr | ~lease->net.s_addr;
if (get_option_uint32(&lease->leasetime, dhcp, DHO_LEASETIME) == 0) {
state->interval = 0;
}
+static int
+dhcp_openudp(struct interface *iface)
+{
+ int s;
+ struct sockaddr_in sin;
+ int n;
+ struct dhcp_state *state;
+#ifdef SO_BINDTODEVICE
+ struct ifreq ifr;
+ char *p;
+#endif
+
+ if ((s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
+ return -1;
+
+ n = 1;
+ if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)) == -1)
+ goto eexit;
+#ifdef SO_BINDTODEVICE
+ memset(&ifr, 0, sizeof(ifr));
+ strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name));
+ /* We can only bind to the real device */
+ p = strchr(ifr.ifr_name, ':');
+ if (p)
+ *p = '\0';
+ if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, &ifr,
+ sizeof(ifr)) == -1)
+ goto eexit;
+#endif
+ /* As we don't use this socket for receiving, set the
+ * * receive buffer to 1 */
+ n = 1;
+ if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n)) == -1)
+ goto eexit;
+ state = D_STATE(iface);
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(DHCP_CLIENT_PORT);
+ sin.sin_addr.s_addr = state->addr.s_addr;
+ if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) == -1)
+ goto eexit;
+
+ state->udp_fd = s;
+ set_cloexec(s);
+ return 0;
+
+eexit:
+ close(s);
+ return -1;
+}
+
+static ssize_t
+dhcp_sendpacket(const struct interface *iface, struct in_addr to,
+ const uint8_t *data, ssize_t len)
+{
+ struct sockaddr_in sin;
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = to.s_addr;
+ sin.sin_port = htons(DHCP_SERVER_PORT);
+ return sendto(D_CSTATE(iface)->udp_fd, data, len, 0,
+ (struct sockaddr *)&sin, sizeof(sin));
+}
+
+static uint16_t
+checksum(const void *data, uint16_t len)
+{
+ const uint8_t *addr = data;
+ uint32_t sum = 0;
+
+ while (len > 1) {
+ sum += addr[0] * 256 + addr[1];
+ addr += 2;
+ len -= 2;
+ }
+
+ if (len == 1)
+ sum += *addr * 256;
+
+ sum = (sum >> 16) + (sum & 0xffff);
+ sum += (sum >> 16);
+
+ sum = htons(sum);
+
+ return ~sum;
+}
+
+static ssize_t
+dhcp_makeudppacket(uint8_t **p, const uint8_t *data, size_t length,
+ struct in_addr source, struct in_addr dest)
+{
+ struct udp_dhcp_packet *udpp;
+ struct ip *ip;
+ struct udphdr *udp;
+
+ udpp = xzalloc(sizeof(*udpp));
+ ip = &udpp->ip;
+ udp = &udpp->udp;
+
+ /* OK, this is important :)
+ * We copy the data to our packet and then create a small part of the
+ * ip structure and an invalid ip_len (basically udp length).
+ * We then fill the udp structure and put the checksum
+ * of the whole packet into the udp checksum.
+ * Finally we complete the ip structure and ip checksum.
+ * If we don't do the ordering like so then the udp checksum will be
+ * broken, so find another way of doing it! */
+
+ memcpy(&udpp->dhcp, data, length);
+
+ ip->ip_p = IPPROTO_UDP;
+ ip->ip_src.s_addr = source.s_addr;
+ if (dest.s_addr == 0)
+ ip->ip_dst.s_addr = INADDR_BROADCAST;
+ else
+ ip->ip_dst.s_addr = dest.s_addr;
+
+ udp->uh_sport = htons(DHCP_CLIENT_PORT);
+ udp->uh_dport = htons(DHCP_SERVER_PORT);
+ udp->uh_ulen = htons(sizeof(*udp) + length);
+ ip->ip_len = udp->uh_ulen;
+ udp->uh_sum = checksum(udpp, sizeof(*udpp));
+
+ ip->ip_v = IPVERSION;
+ ip->ip_hl = sizeof(*ip) >> 2;
+ ip->ip_id = arc4random() & UINT16_MAX;
+ ip->ip_ttl = IPDEFTTL;
+ ip->ip_len = htons(sizeof(*ip) + sizeof(*udp) + length);
+ ip->ip_sum = checksum(ip, sizeof(*ip));
+
+ *p = (uint8_t *)udpp;
+ return sizeof(*ip) + sizeof(*udp) + length;
+}
+
static void
send_message(struct interface *iface, int type,
void (*callback)(void *))
else
to.s_addr = 0;
if (to.s_addr && to.s_addr != INADDR_BROADCAST) {
- r = send_packet(iface, to, (uint8_t *)dhcp, len);
+ r = dhcp_sendpacket(iface, to, (uint8_t *)dhcp, len);
if (r == -1) {
- syslog(LOG_ERR, "%s: send_packet: %m", iface->name);
+ syslog(LOG_ERR, "%s: dhcp_sendpacket: %m", iface->name);
dhcp_close(iface);
}
} else {
- len = make_udp_packet(&udp, (uint8_t *)dhcp, len, from, to);
- r = send_raw_packet(iface, ETHERTYPE_IP, udp, len);
+ len = dhcp_makeudppacket(&udp, (uint8_t *)dhcp, len, from, to);
+ r = ipv4_sendrawpacket(iface, ETHERTYPE_IP, udp, len);
free(udp);
/* If we failed to send a raw packet this normally means
* we don't have the ability to work beneath the IP layer
}
}
-
static void
dhcp_timeout(void *arg)
{
if (ifo->req_addr.s_addr != INADDR_ANY)
return 0;
- if (get_address(ifp->name, &addr, &net, &dst) == 1)
+ if (ipv4_getaddress(ifp->name, &addr, &net, &dst) == 1)
ipv4_handleifa(RTM_NEWADDR, ifp->name, &addr, &net, &dst);
else {
syslog(LOG_INFO,
dhcp_request(ifp);
}
-
void
dhcp_drop(struct interface *iface, const char *reason)
{
/* If the interface already has the address configured
* then we can't ARP for duplicate detection. */
addr.s_addr = state->offer->yiaddr;
- if (has_address(iface->name, &addr, NULL) != 1) {
+ if (ipv4_hasaddress(iface->name, &addr, NULL) != 1) {
state->claims = 0;
state->probes = 0;
state->conflicts = 0;
dhcp_bind(iface);
}
+static ssize_t
+get_udp_data(const uint8_t **data, const uint8_t *udp)
+{
+ struct udp_dhcp_packet p;
+
+ memcpy(&p, udp, sizeof(p));
+ *data = udp + offsetof(struct udp_dhcp_packet, dhcp);
+ return ntohs(p.ip.ip_len) - sizeof(p.ip) - sizeof(p.udp);
+}
+
+static int
+valid_udp_packet(const uint8_t *data, size_t data_len, struct in_addr *from,
+ int noudpcsum)
+{
+ struct udp_dhcp_packet p;
+ uint16_t bytes, udpsum;
+
+ if (data_len < sizeof(p.ip)) {
+ if (from)
+ from->s_addr = INADDR_ANY;
+ errno = EINVAL;
+ return -1;
+ }
+ memcpy(&p, data, MIN(data_len, sizeof(p)));
+ if (from)
+ from->s_addr = p.ip.ip_src.s_addr;
+ if (data_len > sizeof(p)) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (checksum(&p.ip, sizeof(p.ip)) != 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ bytes = ntohs(p.ip.ip_len);
+ if (data_len < bytes) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (noudpcsum == 0) {
+ udpsum = p.udp.uh_sum;
+ p.udp.uh_sum = 0;
+ p.ip.ip_hl = 0;
+ p.ip.ip_v = 0;
+ p.ip.ip_tos = 0;
+ p.ip.ip_len = p.udp.uh_ulen;
+ p.ip.ip_id = 0;
+ p.ip.ip_off = 0;
+ p.ip.ip_ttl = 0;
+ p.ip.ip_sum = 0;
+ if (udpsum && checksum(&p, bytes) != udpsum) {
+ errno = EINVAL;
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
static void
dhcp_handlepacket(void *arg)
{
if (packet == NULL)
packet = xmalloc(udp_dhcp_len);
for(;;) {
- bytes = get_raw_packet(iface, ETHERTYPE_IP,
+ bytes = ipv4_getrawpacket(iface, ETHERTYPE_IP,
packet, udp_dhcp_len, &partialcsum);
if (bytes == 0 || bytes == -1)
break;
state = D_STATE(ifp);
if (state->raw_fd == -1) {
- if ((r = open_socket(ifp, ETHERTYPE_IP)) == -1)
+ if ((r = ipv4_opensocket(ifp, ETHERTYPE_IP)) == -1)
syslog(LOG_ERR, "%s: %s: %m", __func__, ifp->name);
else
eloop_event_add(state->raw_fd, dhcp_handlepacket, ifp);
(state->new->cookie == htonl(MAGIC_COOKIE) ||
ifp->options->options & DHCPCD_INFORM))
{
- if (open_udp_socket(ifp) == -1 && errno != EADDRINUSE) {
- syslog(LOG_ERR, "%s: open_udp_socket: %m", ifp->name);
+ if (dhcp_openudp(ifp) == -1 && errno != EADDRINUSE) {
+ syslog(LOG_ERR, "%s: dhcp_openudp: %m", ifp->name);
r = -1;
}
}
syslog(LOG_ERR, "control_start: %m");
}
- if (init_sockets() == -1) {
- syslog(LOG_ERR, "init_socket: %m");
+ if (open_sockets() == -1) {
+ syslog(LOG_ERR, "open_sockets: %m");
exit(EXIT_FAILURE);
}
if (if_options->options & DHCPCD_LINK) {
}
int
-init_sockets(void)
+open_sockets(void)
{
if ((socket_afnet = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
return -1;
#include "dhcp.h"
#include "dhcp6.h"
#include "if-options.h"
-#include "net.h"
+#include "ipv4.h"
#include "platform.h"
unsigned long long options = 0;
if (p != NULL)
*--p = '/';
else if (net != NULL)
- net->s_addr = get_netmask(addr->s_addr);
+ net->s_addr = ipv4_getnetmask(addr->s_addr);
return 0;
}
free(ifo->config[i++]);
free(ifo->config);
}
- free_routes(ifo->routes);
+ ipv4_freeroutes(ifo->routes);
free(ifo->arping);
free(ifo->blacklist);
free(ifo->fallback);
#include <ctype.h>
#include <errno.h>
+#include <ifaddrs.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include "net.h"
#include "script.h"
+int socket_afnet = -1;
+
static struct rt *routes;
+int
+inet_ntocidr(struct in_addr address)
+{
+ int cidr = 0;
+ uint32_t mask = htonl(address.s_addr);
+
+ while (mask) {
+ cidr++;
+ mask <<= 1;
+ }
+ return cidr;
+}
+
+int
+inet_cidrtoaddr(int cidr, struct in_addr *addr)
+{
+ int ocets;
+
+ if (cidr < 1 || cidr > 32) {
+ errno = EINVAL;
+ return -1;
+ }
+ ocets = (cidr + 7) / 8;
+
+ addr->s_addr = 0;
+ if (ocets > 0) {
+ memset(&addr->s_addr, 255, (size_t)ocets - 1);
+ memset((unsigned char *)&addr->s_addr + (ocets - 1),
+ (256 - (1 << (32 - cidr) % 8)), 1);
+ }
+
+ return 0;
+}
+
+uint32_t
+ipv4_getnetmask(uint32_t addr)
+{
+ uint32_t dst;
+
+ if (addr == 0)
+ return 0;
+
+ dst = htonl(addr);
+ if (IN_CLASSA(dst))
+ return ntohl(IN_CLASSA_NET);
+ if (IN_CLASSB(dst))
+ return ntohl(IN_CLASSB_NET);
+ if (IN_CLASSC(dst))
+ return ntohl(IN_CLASSC_NET);
+
+ return 0;
+}
+
+int
+ipv4_doaddress(const char *ifname,
+ struct in_addr *addr, struct in_addr *net, struct in_addr *dst, int act)
+{
+ struct ifaddrs *ifaddrs, *ifa;
+ const struct sockaddr_in *a, *n, *d;
+ int retval;
+
+ if (getifaddrs(&ifaddrs) == -1)
+ return -1;
+
+ retval = 0;
+ for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr == NULL ||
+ ifa->ifa_addr->sa_family != AF_INET ||
+ strcmp(ifa->ifa_name, ifname) != 0)
+ continue;
+ a = (const struct sockaddr_in *)(void *)ifa->ifa_addr;
+ n = (const struct sockaddr_in *)(void *)ifa->ifa_netmask;
+ if (ifa->ifa_flags & IFF_POINTOPOINT)
+ d = (const struct sockaddr_in *)(void *)
+ ifa->ifa_dstaddr;
+ else
+ d = NULL;
+ if (act == 1) {
+ addr->s_addr = a->sin_addr.s_addr;
+ net->s_addr = n->sin_addr.s_addr;
+ if (dst) {
+ if (ifa->ifa_flags & IFF_POINTOPOINT)
+ dst->s_addr = d->sin_addr.s_addr;
+ else
+ dst->s_addr = INADDR_ANY;
+ }
+ retval = 1;
+ break;
+ }
+ if (addr->s_addr == a->sin_addr.s_addr &&
+ (net == NULL || net->s_addr == n->sin_addr.s_addr))
+ {
+ retval = 1;
+ break;
+ }
+ }
+ freeifaddrs(ifaddrs);
+ return retval;
+}
+
+void
+ipv4_freeroutes(struct rt *rts)
+{
+ struct rt *r;
+
+ while (rts) {
+ r = rts->next;
+ free(rts);
+ rts = r;
+ }
+}
+
static struct rt *
find_route(struct rt *rts, const struct rt *r, struct rt **lrt,
const struct rt *srt)
return -1;
desc_route("adding", rt);
- if (!add_route(rt))
+ if (!ipv4_addroute(rt))
return 0;
if (errno == EEXIST) {
s = D_CSTATE(rt->iface);
else
return -1;
}
- syslog(LOG_ERR, "%s: add_route: %m", rt->iface->name);
+ syslog(LOG_ERR, "%s: ipv4_addroute: %m", rt->iface->name);
return -1;
}
/* We delete and add the route so that we can change metric.
* This also has the nice side effect of flushing ARP entries so
* we don't have to do that manually. */
- del_route(ort);
- if (!add_route(nrt))
+ ipv4_deleteroute(ort);
+ if (!ipv4_addroute(nrt))
return 0;
- syslog(LOG_ERR, "%s: add_route: %m", nrt->iface->name);
+ syslog(LOG_ERR, "%s: ipv4_addroute: %m", nrt->iface->name);
return -1;
}
int retval;
desc_route("deleting", rt);
- retval = del_route(rt);
+ retval = ipv4_deleteroute(rt);
if (retval != 0 && errno != ENOENT && errno != ESRCH)
- syslog(LOG_ERR,"%s: del_route: %m", rt->iface->name);
+ syslog(LOG_ERR,"%s: ipv4_deleteroute: %m", rt->iface->name);
return retval;
}
addr = dhcp->ciaddr;
/* Ensure we have all the needed values */
if (get_option_addr(&net, dhcp, DHO_SUBNETMASK) == -1)
- net.s_addr = get_netmask(addr);
+ net.s_addr = ipv4_getnetmask(addr);
if (net.s_addr == INADDR_BROADCAST || net.s_addr == INADDR_ANY)
return NULL;
rt = malloc(sizeof(*rt));
nrs = rt;
rt = lrt; /* When we loop this makes lrt correct */
}
- free_routes(dnr);
+ ipv4_freeroutes(dnr);
}
/* Remove old routes we used to manage */
d_route(rt);
}
- free_routes(routes);
+ ipv4_freeroutes(routes);
routes = nrs;
}
return 0;
syslog(LOG_DEBUG, "%s: deleting IP address %s/%d",
iface->name, inet_ntoa(state->addr), inet_ntocidr(state->net));
- retval = del_address(iface, &state->addr, &state->net);
+ retval = ipv4_deleteaddress(iface, &state->addr, &state->net);
if (retval == -1 && errno != EADDRNOTAVAIL)
syslog(LOG_ERR, "del_address: %m");
state->addr.s_addr = 0;
/* This also changes netmask */
if (!(ifo->options & DHCPCD_INFORM) ||
- !has_address(ifp->name, &lease->addr, &lease->net))
+ !ipv4_hasaddress(ifp->name, &lease->addr, &lease->net))
{
syslog(LOG_DEBUG, "%s: adding IP address %s/%d",
ifp->name, inet_ntoa(lease->addr),
inet_ntocidr(lease->net));
- if (add_address(ifp,
+ if (ipv4_addaddress(ifp,
&lease->addr, &lease->net, &lease->brd) == -1 &&
errno != EEXIST)
{
- syslog(LOG_ERR, "%s: add_address: %m", __func__);
+ syslog(LOG_ERR, "%s: ipv4_addaddress: %m", __func__);
return;
}
}
rt->iface = ifp;
rt->metric = 0;
if (!find_route(routes, rt, NULL, NULL))
- del_route(rt);
+ ipv4_deleteroute(rt);
free(rt);
}
#ifndef IPV4_H
#define IPV4_H
-#include "net.h"
+#include "dhcpcd.h"
+
+struct rt {
+ struct in_addr dest;
+ struct in_addr net;
+ struct in_addr gate;
+ const struct interface *iface;
+ int metric;
+ struct in_addr src;
+ struct rt *next;
+};
+
+int inet_ntocidr(struct in_addr);
+int inet_cidrtoaddr(int, struct in_addr *);
+uint32_t ipv4_getnetmask(uint32_t);
void ipv4_buildroutes(void);
void ipv4_applyaddr(void *);
void ipv4_handleifa(int, const char *,
struct in_addr *, struct in_addr *, struct in_addr *);
+
+int ipv4_doaddress(const char *,
+ struct in_addr *, struct in_addr *, struct in_addr *, int);
+int if_address(const struct interface *,
+ const struct in_addr *, const struct in_addr *,
+ const struct in_addr *, int);
+#define ipv4_addaddress(iface, addr, net, brd) \
+ if_address(iface, addr, net, brd, 1)
+#define ipv4_deleteaddress(iface, addr, net) \
+ if_address(iface, addr, net, NULL, -1)
+#define ipv4_hasaddress(iface, addr, net) \
+ ipv4_doaddress(iface, addr, net, NULL, 0)
+#define ipv4_getaddress(iface, addr, net, dst) \
+ ipv4_doaddress(iface, addr, net, dst, 1)
+
+int if_route(const struct rt *rt, int);
+#define ipv4_addroute(rt) if_route(rt, 1)
+#define ipv4_changeroute(rt) if_route(rt, 0)
+#define ipv4_deleteroute(rt) if_route(rt, -1)
+#define del_src_route(rt) i_route(rt, -2);
+void ipv4_freeroutes(struct rt *);
+
+int ipv4_opensocket(struct interface *, int);
+ssize_t ipv4_sendrawpacket(const struct interface *,
+ int, const void *, ssize_t);
+ssize_t ipv4_getrawpacket(struct interface *, int, void *, ssize_t, int *);
+
#endif
#include "config.h"
#include "common.h"
#include "dhcp.h"
-#include "net.h"
+#include "ipv4.h"
#include "bpf-filter.h"
/* Broadcast address for IPoIB */
};
int
-open_socket(struct interface *ifp, int protocol)
+ipv4_opensocket(struct interface *ifp, int protocol)
{
int s;
union sockunion {
}
ssize_t
-send_raw_packet(const struct interface *ifp, int protocol,
+ipv4_sendrawpacket(const struct interface *ifp, int protocol,
const void *data, ssize_t len)
{
const struct dhcp_state *state;
}
ssize_t
-get_raw_packet(struct interface *ifp, int protocol,
+ipv4_getrawpacket(struct interface *ifp, int protocol,
void *data, ssize_t len, int *partialcsum)
{
struct iovec iov = {
#include <sys/types.h>
#include <sys/ioctl.h>
-#include <sys/param.h>
#include <sys/socket.h>
-#include <sys/time.h>
-#include <arpa/inet.h>
#include <net/if.h>
#include <net/if_arp.h>
#ifdef AF_LINK
# include <net/if_dl.h>
# include <net/if_types.h>
#endif
-#include <netinet/in_systm.h>
-#include <netinet/in.h>
-#include <netinet/ip.h>
-#define __FAVOR_BSD /* Nasty glibc hack so we can use BSD semantics for UDP */
-#include <netinet/udp.h>
-#undef __FAVOR_BSD
#ifdef AF_PACKET
# include <netpacket/packet.h>
#endif
#include "if-options.h"
#include "ipv6rs.h"
#include "net.h"
-#include "signals.h"
static char hwaddr_buffer[(HWADDR_LEN * 3) + 1 + 1024];
-int socket_afnet = -1;
-
-int
-inet_ntocidr(struct in_addr address)
-{
- int cidr = 0;
- uint32_t mask = htonl(address.s_addr);
-
- while (mask) {
- cidr++;
- mask <<= 1;
- }
- return cidr;
-}
-
-int
-inet_cidrtoaddr(int cidr, struct in_addr *addr)
-{
- int ocets;
-
- if (cidr < 1 || cidr > 32) {
- errno = EINVAL;
- return -1;
- }
- ocets = (cidr + 7) / 8;
-
- addr->s_addr = 0;
- if (ocets > 0) {
- memset(&addr->s_addr, 255, (size_t)ocets - 1);
- memset((unsigned char *)&addr->s_addr + (ocets - 1),
- (256 - (1 << (32 - cidr) % 8)), 1);
- }
-
- return 0;
-}
-
-uint32_t
-get_netmask(uint32_t addr)
-{
- uint32_t dst;
-
- if (addr == 0)
- return 0;
-
- dst = htonl(addr);
- if (IN_CLASSA(dst))
- return ntohl(IN_CLASSA_NET);
- if (IN_CLASSB(dst))
- return ntohl(IN_CLASSB_NET);
- if (IN_CLASSC(dst))
- return ntohl(IN_CLASSC_NET);
-
- return 0;
-}
-
char *
hwaddr_ntoa(const unsigned char *hwaddr, size_t hwlen)
{
return ifs;
}
-int
-do_address(const char *ifname,
- struct in_addr *addr, struct in_addr *net, struct in_addr *dst, int act)
-{
- struct ifaddrs *ifaddrs, *ifa;
- const struct sockaddr_in *a, *n, *d;
- int retval;
-
- if (getifaddrs(&ifaddrs) == -1)
- return -1;
-
- retval = 0;
- for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) {
- if (ifa->ifa_addr == NULL ||
- ifa->ifa_addr->sa_family != AF_INET ||
- strcmp(ifa->ifa_name, ifname) != 0)
- continue;
- a = (const struct sockaddr_in *)(void *)ifa->ifa_addr;
- n = (const struct sockaddr_in *)(void *)ifa->ifa_netmask;
- if (ifa->ifa_flags & IFF_POINTOPOINT)
- d = (const struct sockaddr_in *)(void *)
- ifa->ifa_dstaddr;
- else
- d = NULL;
- if (act == 1) {
- addr->s_addr = a->sin_addr.s_addr;
- net->s_addr = n->sin_addr.s_addr;
- if (dst) {
- if (ifa->ifa_flags & IFF_POINTOPOINT)
- dst->s_addr = d->sin_addr.s_addr;
- else
- dst->s_addr = INADDR_ANY;
- }
- retval = 1;
- break;
- }
- if (addr->s_addr == a->sin_addr.s_addr &&
- (net == NULL || net->s_addr == n->sin_addr.s_addr))
- {
- retval = 1;
- break;
- }
- }
- freeifaddrs(ifaddrs);
- return retval;
-}
-
int
do_mtu(const char *ifname, short int mtu)
{
return -1;
return ifr.ifr_mtu;
}
-
-void
-free_routes(struct rt *routes)
-{
- struct rt *r;
-
- while (routes) {
- r = routes->next;
- free(routes);
- routes = r;
- }
-}
-
-int
-open_udp_socket(struct interface *iface)
-{
- int s;
- struct sockaddr_in sin;
- int n;
- struct dhcp_state *state;
-#ifdef SO_BINDTODEVICE
- struct ifreq ifr;
- char *p;
-#endif
-
- if ((s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
- return -1;
-
- n = 1;
- if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)) == -1)
- goto eexit;
-#ifdef SO_BINDTODEVICE
- memset(&ifr, 0, sizeof(ifr));
- strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name));
- /* We can only bind to the real device */
- p = strchr(ifr.ifr_name, ':');
- if (p)
- *p = '\0';
- if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, &ifr,
- sizeof(ifr)) == -1)
- goto eexit;
-#endif
- /* As we don't use this socket for receiving, set the
- * receive buffer to 1 */
- n = 1;
- if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n)) == -1)
- goto eexit;
- state = D_STATE(iface);
- memset(&sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
- sin.sin_port = htons(DHCP_CLIENT_PORT);
- sin.sin_addr.s_addr = state->addr.s_addr;
- if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) == -1)
- goto eexit;
-
- state->udp_fd = s;
- set_cloexec(s);
- return 0;
-
-eexit:
- close(s);
- return -1;
-}
-
-ssize_t
-send_packet(const struct interface *iface, struct in_addr to,
- const uint8_t *data, ssize_t len)
-{
- struct sockaddr_in sin;
-
- memset(&sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = to.s_addr;
- sin.sin_port = htons(DHCP_SERVER_PORT);
- return sendto(D_CSTATE(iface)->udp_fd, data, len, 0,
- (struct sockaddr *)&sin, sizeof(sin));
-}
-
-struct udp_dhcp_packet
-{
- struct ip ip;
- struct udphdr udp;
- struct dhcp_message dhcp;
-};
-const size_t udp_dhcp_len = sizeof(struct udp_dhcp_packet);
-
-static uint16_t
-checksum(const void *data, uint16_t len)
-{
- const uint8_t *addr = data;
- uint32_t sum = 0;
-
- while (len > 1) {
- sum += addr[0] * 256 + addr[1];
- addr += 2;
- len -= 2;
- }
-
- if (len == 1)
- sum += *addr * 256;
-
- sum = (sum >> 16) + (sum & 0xffff);
- sum += (sum >> 16);
-
- sum = htons(sum);
-
- return ~sum;
-}
-
-ssize_t
-make_udp_packet(uint8_t **packet, const uint8_t *data, size_t length,
- struct in_addr source, struct in_addr dest)
-{
- struct udp_dhcp_packet *udpp;
- struct ip *ip;
- struct udphdr *udp;
-
- udpp = xzalloc(sizeof(*udpp));
- ip = &udpp->ip;
- udp = &udpp->udp;
-
- /* OK, this is important :)
- * We copy the data to our packet and then create a small part of the
- * ip structure and an invalid ip_len (basically udp length).
- * We then fill the udp structure and put the checksum
- * of the whole packet into the udp checksum.
- * Finally we complete the ip structure and ip checksum.
- * If we don't do the ordering like so then the udp checksum will be
- * broken, so find another way of doing it! */
-
- memcpy(&udpp->dhcp, data, length);
-
- ip->ip_p = IPPROTO_UDP;
- ip->ip_src.s_addr = source.s_addr;
- if (dest.s_addr == 0)
- ip->ip_dst.s_addr = INADDR_BROADCAST;
- else
- ip->ip_dst.s_addr = dest.s_addr;
-
- udp->uh_sport = htons(DHCP_CLIENT_PORT);
- udp->uh_dport = htons(DHCP_SERVER_PORT);
- udp->uh_ulen = htons(sizeof(*udp) + length);
- ip->ip_len = udp->uh_ulen;
- udp->uh_sum = checksum(udpp, sizeof(*udpp));
-
- ip->ip_v = IPVERSION;
- ip->ip_hl = sizeof(*ip) >> 2;
- ip->ip_id = arc4random() & UINT16_MAX;
- ip->ip_ttl = IPDEFTTL;
- ip->ip_len = htons(sizeof(*ip) + sizeof(*udp) + length);
- ip->ip_sum = checksum(ip, sizeof(*ip));
-
- *packet = (uint8_t *)udpp;
- return sizeof(*ip) + sizeof(*udp) + length;
-}
-
-ssize_t
-get_udp_data(const uint8_t **data, const uint8_t *udp)
-{
- struct udp_dhcp_packet packet;
-
- memcpy(&packet, udp, sizeof(packet));
- *data = udp + offsetof(struct udp_dhcp_packet, dhcp);
- return ntohs(packet.ip.ip_len) -
- sizeof(packet.ip) -
- sizeof(packet.udp);
-}
-
-int
-valid_udp_packet(const uint8_t *data, size_t data_len, struct in_addr *from,
- int noudpcsum)
-{
- struct udp_dhcp_packet packet;
- uint16_t bytes, udpsum;
-
- if (data_len < sizeof(packet.ip)) {
- if (from)
- from->s_addr = INADDR_ANY;
- errno = EINVAL;
- return -1;
- }
- memcpy(&packet, data, MIN(data_len, sizeof(packet)));
- if (from)
- from->s_addr = packet.ip.ip_src.s_addr;
- if (data_len > sizeof(packet)) {
- errno = EINVAL;
- return -1;
- }
- if (checksum(&packet.ip, sizeof(packet.ip)) != 0) {
- errno = EINVAL;
- return -1;
- }
-
- bytes = ntohs(packet.ip.ip_len);
- if (data_len < bytes) {
- errno = EINVAL;
- return -1;
- }
-
- if (noudpcsum == 0) {
- udpsum = packet.udp.uh_sum;
- packet.udp.uh_sum = 0;
- packet.ip.ip_hl = 0;
- packet.ip.ip_v = 0;
- packet.ip.ip_tos = 0;
- packet.ip.ip_len = packet.udp.uh_ulen;
- packet.ip.ip_id = 0;
- packet.ip.ip_off = 0;
- packet.ip.ip_ttl = 0;
- packet.ip.ip_sum = 0;
- if (udpsum && checksum(&packet, bytes) != udpsum) {
- errno = EINVAL;
- return -1;
- }
- }
-
- return 0;
-}
# define IN_LINKLOCAL(addr) ((addr & IN_CLASSB_NET) == LINKLOCAL_ADDR)
#endif
-struct rt {
- struct in_addr dest;
- struct in_addr net;
- struct in_addr gate;
- const struct interface *iface;
- int metric;
- struct in_addr src;
- struct rt *next;
-};
-
extern int socket_afnet;
-uint32_t get_netmask(uint32_t);
+int open_sockets(void);
+
char *hwaddr_ntoa(const unsigned char *, size_t);
size_t hwaddr_aton(unsigned char *, const char *);
#define get_mtu(iface) do_mtu(iface, 0)
#define set_mtu(iface, mtu) do_mtu(iface, mtu)
-int inet_ntocidr(struct in_addr);
-int inet_cidrtoaddr(int, struct in_addr *);
-
int up_interface(struct interface *);
int if_conf(struct interface *);
int if_init(struct interface *);
-int do_address(const char *,
- struct in_addr *, struct in_addr *, struct in_addr *, int);
-int if_address(const struct interface *,
- const struct in_addr *, const struct in_addr *,
- const struct in_addr *, int);
-#define add_address(iface, addr, net, brd) \
- if_address(iface, addr, net, brd, 1)
-#define del_address(iface, addr, net) \
- if_address(iface, addr, net, NULL, -1)
-#define has_address(iface, addr, net) \
- do_address(iface, addr, net, NULL, 0)
-#define get_address(iface, addr, net, dst) \
- do_address(iface, addr, net, dst, 1)
-
-int if_route(const struct rt *rt, int);
-#define add_route(rt) if_route(rt, 1)
-#define change_route(rt) if_route(rt, 0)
-#define del_route(rt) if_route(rt, -1)
-#define del_src_route(rt) if_route(rt, -2);
-void free_routes(struct rt *);
-
int if_address6(const struct interface *, const struct ipv6_addr *, int);
#define add_address6(ifp, a) if_address6(ifp, a, 1)
#define del_address6(ifp, a) if_address6(ifp, a, -1)
#define del_route6(rt) if_route6(rt, -1)
#define del_src_route6(rt) if_route6(rt, -2);
-int open_udp_socket(struct interface *);
-extern const size_t udp_dhcp_len;
-ssize_t make_udp_packet(uint8_t **, const uint8_t *, size_t,
- struct in_addr, struct in_addr);
-ssize_t get_udp_data(const uint8_t **, const uint8_t *);
-int valid_udp_packet(const uint8_t *, size_t, struct in_addr *, int);
-
-int open_socket(struct interface *, int);
-ssize_t send_packet(const struct interface *, struct in_addr,
- const uint8_t *, ssize_t);
-ssize_t send_raw_packet(const struct interface *, int,
- const void *, ssize_t);
-ssize_t get_raw_packet(struct interface *, int, void *, ssize_t, int *);
-
-int init_sockets(void);
int open_link_socket(void);
int manage_link(int);
int carrier_status(struct interface *);