summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKenneth R Westerback <krw@cvs.openbsd.org>2012-09-18 09:34:10 +0000
committerKenneth R Westerback <krw@cvs.openbsd.org>2012-09-18 09:34:10 +0000
commit3ca5cf3cbd3e1c182a2e36bcd033ef9bf7540b6d (patch)
tree232de3a9325ab13d2a0b13854640922de4f4b601
parentd969a0350bb560c21fa288513e0acdb96c341448 (diff)
Don't accept leases that offer a subnet that is already configured
on an interface. Crude hammer that may be refined as needed. Feedback from tedu@, beck@, sthen@ claudio@
-rw-r--r--sbin/dhclient/dhclient.c9
-rw-r--r--sbin/dhclient/dhcpd.h3
-rw-r--r--sbin/dhclient/dispatch.c58
3 files changed, 67 insertions, 3 deletions
diff --git a/sbin/dhclient/dhclient.c b/sbin/dhclient/dhclient.c
index 93298b2f729..95fb1144080 100644
--- a/sbin/dhclient/dhclient.c
+++ b/sbin/dhclient/dhclient.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: dhclient.c,v 1.155 2012/09/17 20:30:17 krw Exp $ */
+/* $OpenBSD: dhclient.c,v 1.156 2012/09/18 09:34:09 krw Exp $ */
/*
* Copyright 2004 Henning Brauer <henning@openbsd.org>
@@ -758,6 +758,13 @@ dhcpoffer(struct iaddr client_addr, struct option_data *options)
return;
}
+ /*
+ * Reject offers whose subnet is already configured on another
+ * interface.
+ */
+ if (subnet_exists(lease))
+ return;
+
/* If this lease was acquired through a BOOTREPLY, record that
fact. */
if (!options[DHO_DHCP_MESSAGE_TYPE].len)
diff --git a/sbin/dhclient/dhcpd.h b/sbin/dhclient/dhcpd.h
index b899e0dc703..d0e7cabce62 100644
--- a/sbin/dhclient/dhcpd.h
+++ b/sbin/dhclient/dhcpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: dhcpd.h,v 1.80 2012/09/01 19:08:42 krw Exp $ */
+/* $OpenBSD: dhcpd.h,v 1.81 2012/09/18 09:34:09 krw Exp $ */
/*
* Copyright (c) 2004 Henning Brauer <henning@openbsd.org>
@@ -256,6 +256,7 @@ void cancel_timeout(void);
int interface_status(char *);
int interface_link_forceup(char *);
int get_rdomain(char *);
+int subnet_exists(struct client_lease *);
/* tables.c */
extern const struct option dhcp_options[256];
diff --git a/sbin/dhclient/dispatch.c b/sbin/dhclient/dispatch.c
index 863430d2b9e..d5662e3f805 100644
--- a/sbin/dhclient/dispatch.c
+++ b/sbin/dhclient/dispatch.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: dispatch.c,v 1.57 2012/09/17 12:10:46 krw Exp $ */
+/* $OpenBSD: dispatch.c,v 1.58 2012/09/18 09:34:09 krw Exp $ */
/*
* Copyright 2004 Henning Brauer <henning@openbsd.org>
@@ -335,3 +335,59 @@ get_rdomain(char *name)
close(s);
return rv;
}
+
+int
+subnet_exists(struct client_lease *l)
+ {
+ struct ifaddrs *ifap, *ifa;
+ in_addr_t mymask, myaddr, mynet, hismask, hisaddr, hisnet;
+ int myrdomain, hisrdomain;
+
+ bcopy(l->options[DHO_SUBNET_MASK].data, &mymask, 4);
+ bcopy(l->address.iabuf, &myaddr, 4);
+ mynet = mymask & myaddr;
+
+ myrdomain = get_rdomain(ifi->name);
+
+ if (getifaddrs(&ifap) != 0)
+ error("getifaddrs failed");
+
+ for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
+ if (strcmp(ifi->name, ifa->ifa_name) == 0)
+ continue;
+
+ if (ifa->ifa_addr->sa_family != AF_INET)
+ continue;
+
+ hisrdomain = get_rdomain(ifi->name);
+ if (hisrdomain != myrdomain)
+ continue;
+
+ hismask = ((struct sockaddr_in *)ifa->ifa_netmask)->
+ sin_addr.s_addr;
+ hisaddr = ((struct sockaddr_in *)ifa->ifa_addr)->
+ sin_addr.s_addr;
+ hisnet = hisaddr & hismask;
+
+ if (hisnet == 0)
+ continue;
+
+ /* Would his packets go out *my* interface? */
+ if (mynet == (hisaddr & mymask)) {
+ note("interface %s already has the offered subnet!",
+ ifa->ifa_name);
+ return (1);
+ }
+
+ /* Would my packets go out *his* interface? */
+ if (hisnet == (myaddr & hismask)) {
+ note("interface %s already has the offered subnet!",
+ ifa->ifa_name);
+ return (1);
+ }
+ }
+
+ freeifaddrs(ifap);
+
+ return (0);
+ }