summaryrefslogtreecommitdiff
path: root/gdhcp/common.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdhcp/common.c')
-rwxr-xr-x[-rw-r--r--]gdhcp/common.c61
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);