diff options
Diffstat (limited to 'gdhcp/common.c')
-rwxr-xr-x[-rw-r--r--] | gdhcp/common.c | 61 |
1 files changed, 53 insertions, 8 deletions
diff --git a/gdhcp/common.c b/gdhcp/common.c index ac6b1250..6d457ac5 100644..100755 --- a/gdhcp/common.c +++ b/gdhcp/common.c @@ -35,6 +35,7 @@ #include <netpacket/packet.h> #include <net/ethernet.h> #include <arpa/inet.h> +#include <fcntl.h> #include "gdhcp.h" #include "common.h" @@ -58,6 +59,42 @@ static const DHCPOption client_options[] = { { OPTION_UNKNOWN, 0x00 }, }; +#define URANDOM "/dev/urandom" +static int random_fd = -1; + +int dhcp_get_random(uint64_t *val) +{ + int r; + + if (random_fd < 0) { + random_fd = open(URANDOM, O_RDONLY); + if (random_fd < 0) { + r = -errno; + *val = random(); + + return r; + } + } + + if (read(random_fd, val, sizeof(uint64_t)) < 0) { + r = -errno; + *val = random(); + + return r; + } + + return 0; +} + +void dhcp_cleanup_random(void) +{ + if (random_fd < 0) + return; + + close(random_fd); + random_fd = -1; +} + GDHCPOptionType dhcp_get_code_type(uint8_t code) { int i; @@ -421,12 +458,14 @@ void dhcp_init_header(struct dhcp_packet *packet, char type) void dhcpv6_init_header(struct dhcpv6_packet *packet, uint8_t type) { int id; + uint64_t rand; memset(packet, 0, sizeof(*packet)); packet->message = type; - id = random(); + dhcp_get_random(&rand); + id = rand; packet->transaction_id[0] = (id >> 16) & 0xff; packet->transaction_id[1] = (id >> 8) & 0xff; @@ -499,19 +538,14 @@ uint16_t dhcp_checksum(void *addr, int count) static const struct in6_addr in6addr_all_dhcp_relay_agents_and_servers_mc = IN6ADDR_ALL_DHCP_RELAY_AGENTS_AND_SERVERS_MC_INIT; -/* from netinet/in.h */ -struct in6_pktinfo { - struct in6_addr ipi6_addr; /* src/dst IPv6 address */ - unsigned int ipi6_ifindex; /* send/recv interface index */ -}; - int dhcpv6_send_packet(int index, struct dhcpv6_packet *dhcp_pkt, int len) { struct msghdr m; struct iovec v; struct in6_pktinfo *pktinfo; struct cmsghdr *cmsg; - int fd, ret; + int fd, ret, opt = 1; + struct sockaddr_in6 src; struct sockaddr_in6 dst; void *control_buf; size_t control_buf_len; @@ -520,6 +554,17 @@ int dhcpv6_send_packet(int index, struct dhcpv6_packet *dhcp_pkt, int len) if (fd < 0) return -errno; + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); + + memset(&src, 0, sizeof(src)); + src.sin6_family = AF_INET6; + src.sin6_port = htons(DHCPV6_CLIENT_PORT); + + if (bind(fd, (struct sockaddr *) &src, sizeof(src)) <0) { + close(fd); + return -errno; + } + memset(&dst, 0, sizeof(dst)); dst.sin6_family = AF_INET6; dst.sin6_port = htons(DHCPV6_SERVER_PORT); |