summaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
authorFrancis Dupont <fdupont@isc.org>2017-12-23 01:18:23 +0100
committerFrancis Dupont <fdupont@isc.org>2017-12-23 01:18:23 +0100
commit563f0b8aef9558a900f215dfccc571eab99a0223 (patch)
tree4d5ce8719fe415d089569f5f98ca84c944a42aaf /common
parent0d6d300fec8b26c9e854095a4a29158186b69172 (diff)
downloadisc-dhcp-563f0b8aef9558a900f215dfccc571eab99a0223.tar.gz
Merged rt44535 (relay port)
Diffstat (limited to 'common')
-rw-r--r--common/bpf.c57
-rw-r--r--common/discover.c43
-rw-r--r--common/dlpi.c4
-rw-r--r--common/lpf.c19
-rw-r--r--common/nit.c4
-rw-r--r--common/packet.c11
-rw-r--r--common/raw.c4
-rw-r--r--common/socket.c70
-rw-r--r--common/tables.c16
-rw-r--r--common/upf.c3
10 files changed, 211 insertions, 20 deletions
diff --git a/common/bpf.c b/common/bpf.c
index dc41f809..16076fea 100644
--- a/common/bpf.c
+++ b/common/bpf.c
@@ -192,12 +192,51 @@ struct bpf_insn dhcp_bpf_filter [] = {
BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, 67, 0, 1), /* patch */
/* If we passed all the tests, ask for the whole packet. */
- BPF_STMT(BPF_RET+BPF_K, (u_int)-1),
+ BPF_STMT (BPF_RET + BPF_K, (u_int)-1),
/* Otherwise, drop it. */
- BPF_STMT(BPF_RET+BPF_K, 0),
+ BPF_STMT (BPF_RET + BPF_K, 0),
};
+#if defined(RELAY_PORT)
+/*
+ * For relay port extension
+ */
+struct bpf_insn dhcp_bpf_relay_filter [] = {
+ /* Make sure this is an IP packet... */
+ BPF_STMT (BPF_LD + BPF_H + BPF_ABS, 12),
+ BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 10),
+
+ /* Make sure it's a UDP packet... */
+ BPF_STMT (BPF_LD + BPF_B + BPF_ABS, 23),
+ BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 8),
+
+ /* Make sure this isn't a fragment... */
+ BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20),
+ BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 6, 0),
+
+ /* Get the IP header length... */
+ BPF_STMT (BPF_LDX + BPF_B + BPF_MSH, 14),
+
+ /* Make sure it's to the right port... */
+ BPF_STMT (BPF_LD + BPF_H + BPF_IND, 16),
+ BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, 67, 2, 0), /* patch */
+
+ /* relay can have an alternative port... */
+ BPF_STMT (BPF_LD + BPF_H + BPF_IND, 16),
+ BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, 67, 0, 1), /* patch */
+
+ /* If we passed all the tests, ask for the whole packet. */
+ BPF_STMT (BPF_RET + BPF_K, (u_int)-1),
+
+ /* Otherwise, drop it. */
+ BPF_STMT (BPF_RET + BPF_K, 0),
+};
+
+int dhcp_bpf_relay_filter_len =
+ sizeof dhcp_bpf_relay_filter / sizeof (struct bpf_insn);
+#endif
+
#if defined (DEC_FDDI)
struct bpf_insn *bpf_fddi_filter = NULL;
#endif
@@ -309,7 +348,19 @@ void if_register_receive (info)
/* Patch the server port into the BPF program...
XXX changes to filter program may require changes
to the insn number(s) used below! XXX */
- dhcp_bpf_filter [8].k = ntohs (local_port);
+#if defined(RELAY_PORT)
+ if (relay_port) {
+ /*
+ * If user defined relay UDP port, we need to filter
+ * also on the user UDP port.
+ */
+ p.bf_len = dhcp_bpf_relay_filter_len;
+ p.bf_insns = dhcp_bpf_relay_filter;
+
+ dhcp_bpf_relay_filter [10].k = ntohs (relay_port);
+ }
+#endif
+ p.bf_insns [8].k = ntohs (local_port);
if (ioctl (info -> rfdesc, BIOCSETF, &p) < 0)
log_fatal ("Can't install packet filter program: %m");
diff --git a/common/discover.c b/common/discover.c
index f81d63f7..6ef88529 100644
--- a/common/discover.c
+++ b/common/discover.c
@@ -44,6 +44,7 @@ int interfaces_invalidated;
int quiet_interface_discovery;
u_int16_t local_port;
u_int16_t remote_port;
+u_int16_t relay_port = 0;
int dhcpv4_over_dhcpv6 = 0;
int (*dhcp_interface_setup_hook) (struct interface_info *, struct iaddr *);
int (*dhcp_interface_discovery_hook) (struct interface_info *);
@@ -581,6 +582,10 @@ discover_interfaces(int state) {
int ir;
isc_result_t status;
int wifcount = 0;
+#ifdef RELAY_PORT
+ int updone = 0;
+ int downdone = 0;
+#endif
static int setup_fallback = 0;
@@ -946,9 +951,39 @@ discover_interfaces(int state) {
switch (local_family) {
#ifdef DHCPv6
case AF_INET6:
+#ifdef RELAY_PORT
+#define UPSTREAM(ifp) \
+ ((ifp->flags & INTERFACE_STREAMS) == INTERFACE_UPSTREAM)
+#define DOWNSTREAM(ifp) \
+ ((ifp->flags & INTERFACE_STREAMS) == INTERFACE_DOWNSTREAM)
+
+ if (relay_port) {
+ /*
+ * The normal IPv6 relay only needs one
+ * socket as long as we find an interface.
+ * When user relay port is defined, and we
+ * have two different UDP ports. One to
+ * receive from DHCP client with port 547,
+ * and the other is user defined for sending
+ * to the server or upstream relay agent.
+ * Thus we need to register sockets for one
+ * upstream and one downstream interfaces.
+ */
+ if (updone && UPSTREAM(tmp))
+ continue;
+ if (downdone && DOWNSTREAM(tmp))
+ continue;
+ }
+#endif
status = omapi_register_io_object((omapi_object_t *)tmp,
if_readsocket,
0, got_one_v6, 0, 0);
+#ifdef RELAY_PORT
+ if (UPSTREAM(tmp))
+ updone++;
+ else
+ downdone++;
+#endif
break;
#endif /* DHCPv6 */
case AF_INET:
@@ -970,8 +1005,12 @@ discover_interfaces(int state) {
* dynamically adding and removing interfaces, but
* we're well beyond that point in terms of mess.
*/
- if (((state == DISCOVER_SERVER) || (state == DISCOVER_RELAY)) &&
- (local_family == AF_INET6))
+ if (((state == DISCOVER_SERVER) || (state == DISCOVER_RELAY))
+ && (local_family == AF_INET6)
+#if defined(RELAY_PORT)
+ && ((relay_port == 0) || (updone && downdone))
+#endif
+ )
break;
#endif
} /* for (tmp = interfaces; ... */
diff --git a/common/dlpi.c b/common/dlpi.c
index b459dc6d..3990bf12 100644
--- a/common/dlpi.c
+++ b/common/dlpi.c
@@ -409,6 +409,10 @@ void if_deregister_send (info)
XXX Changes to the filter program may require changes to the constant
offsets used in if_register_send to patch the NIT program! XXX */
+#if defined(RELAY_PORT)
+#error "Relay port is not yet supported for DLPI"
+#endif
+
void if_register_receive (info)
struct interface_info *info;
{
diff --git a/common/lpf.c b/common/lpf.c
index 6e6ba014..82a279bb 100644
--- a/common/lpf.c
+++ b/common/lpf.c
@@ -177,6 +177,11 @@ void if_deregister_send (info)
extern struct sock_filter dhcp_bpf_filter [];
extern int dhcp_bpf_filter_len;
+#if defined(RELAY_PORT)
+extern struct sock_filter dhcp_bpf_relay_filter [];
+extern int dhcp_bpf_relay_filter_len;
+#endif
+
#if defined (HAVE_TR_SUPPORT)
extern struct sock_filter dhcp_bpf_tr_filter [];
extern int dhcp_bpf_tr_filter_len;
@@ -256,7 +261,19 @@ static void lpf_gen_filter_setup (info)
/* Patch the server port into the LPF program...
XXX changes to filter program may require changes
to the insn number(s) used below! XXX */
- dhcp_bpf_filter [8].k = ntohs ((short)local_port);
+#if defined(RELAY_PORT)
+ if (relay_port) {
+ /*
+ * If user defined relay UDP port, we need to filter
+ * also on the user UDP port.
+ */
+ p.len = dhcp_bpf_relay_filter_len;
+ p.filter = dhcp_bpf_relay_filter;
+
+ dhcp_bpf_relay_filter [10].k = ntohs (relay_port);
+ }
+#endif
+ dhcp_bpf_filter [8].k = ntohs (local_port);
if (setsockopt (info -> rfdesc, SOL_SOCKET, SO_ATTACH_FILTER, &p,
sizeof p) < 0) {
diff --git a/common/nit.c b/common/nit.c
index 1e14ebb7..d822c151 100644
--- a/common/nit.c
+++ b/common/nit.c
@@ -172,6 +172,10 @@ void if_deregister_send (info)
XXX Changes to the filter program may require changes to the constant
offsets used in if_register_send to patch the NIT program! XXX */
+#if defined(RELAY_PORT)
+#error "Relay port is not yet supported for NIT"
+#endif
+
void if_register_receive (info)
struct interface_info *info;
{
diff --git a/common/packet.c b/common/packet.c
index d6907fe0..f3f62c19 100644
--- a/common/packet.c
+++ b/common/packet.c
@@ -167,6 +167,12 @@ void assemble_udp_ip_header (interface, buf, bufix,
/* Fill out the UDP header */
udp.uh_sport = local_port; /* XXX */
udp.uh_dport = port; /* XXX */
+#if defined(RELAY_PORT)
+ /* Change to relay port defined if sending to server */
+ if (relay_port && (port == htons(67))) {
+ udp.uh_sport = relay_port;
+ }
+#endif
udp.uh_ulen = htons(sizeof(udp) + len);
memset (&udp.uh_sum, 0, sizeof udp.uh_sum);
@@ -296,7 +302,12 @@ decode_udp_ip_header(struct interface_info *interface,
return -1;
/* Is it to the port we're serving? */
+#if defined(RELAY_PORT)
+ if ((udp.uh_dport != local_port) &&
+ ((relay_port == 0) || (udp.uh_dport != relay_port)))
+#else
if (udp.uh_dport != local_port)
+#endif
return -1;
#endif /* USERLAND_FILTER */
diff --git a/common/raw.c b/common/raw.c
index 3ad0bfd2..5c88b25e 100644
--- a/common/raw.c
+++ b/common/raw.c
@@ -55,14 +55,14 @@ void if_register_send (info)
/* Set up the address we're going to connect to. */
name.sin_family = AF_INET;
- name.sin_port = local_port;
+ name.sin_port = relay_port ? relay_port : local_port;
name.sin_addr.s_addr = htonl (INADDR_BROADCAST);
memset (name.sin_zero, 0, sizeof (name.sin_zero));
/* List addresses on which we're listening. */
if (!quiet_interface_discovery)
log_info ("Sending on %s, port %d",
- piaddr (info -> address), htons (local_port));
+ piaddr (info -> address), htons (name.sin_port));
if ((sock = socket (AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
log_fatal ("Can't create dhcp socket: %m");
diff --git a/common/socket.c b/common/socket.c
index 8879bc20..483eb9c3 100644
--- a/common/socket.c
+++ b/common/socket.c
@@ -65,6 +65,10 @@
static int no_global_v6_socket = 0;
static unsigned int global_v6_socket_references = 0;
static int global_v6_socket = -1;
+#if defined(RELAY_PORT)
+static unsigned int relay_port_v6_socket_references = 0;
+static int relay_port_v6_socket = -1;
+#endif
static void if_register_multicast(struct interface_info *info);
#endif
@@ -157,6 +161,11 @@ if_register_socket(struct interface_info *info, int family,
addr6 = (struct sockaddr_in6 *)&name;
addr6->sin6_family = AF_INET6;
addr6->sin6_port = local_port;
+#if defined(RELAY_PORT)
+ if (relay_port &&
+ ((info->flags & INTERFACE_STREAMS) == INTERFACE_UPSTREAM))
+ addr6->sin6_port = relay_port;
+#endif
/* A server feature */
if (bind_local_address6) {
memcpy(&addr6->sin6_addr,
@@ -187,7 +196,7 @@ if_register_socket(struct interface_info *info, int family,
default:
addr = (struct sockaddr_in *)&name;
addr->sin_family = AF_INET;
- addr->sin_port = local_port;
+ addr->sin_port = relay_port ? relay_port : local_port;
memcpy(&addr->sin_addr,
&local_address,
sizeof(addr->sin_addr));
@@ -496,6 +505,10 @@ if_register6(struct interface_info *info, int do_multicast) {
log_fatal("Impossible condition at %s:%d", MDL);
}
+#if defined(RELAY_PORT)
+ if (!relay_port ||
+ ((info->flags & INTERFACE_STREAMS) == INTERFACE_DOWNSTREAM)) {
+#endif
if (global_v6_socket_references == 0) {
global_v6_socket = if_register_socket(info, AF_INET6,
&req_multi, NULL);
@@ -527,6 +540,30 @@ if_register6(struct interface_info *info, int do_multicast) {
info->wfdesc = global_v6_socket;
global_v6_socket_references++;
+#if defined(RELAY_PORT)
+ } else {
+ /*
+ * If relay port is defined, we need to register one
+ * IPv6 UPD socket to handle upstream server or relay agent
+ * with a non-547 UDP local port.
+ */
+ if ((relay_port_v6_socket_references == 0) &&
+ ((info->flags & INTERFACE_STREAMS) == INTERFACE_UPSTREAM)) {
+ relay_port_v6_socket = if_register_socket(info, AF_INET6,
+ &req_multi, NULL);
+ if (relay_port_v6_socket < 0) {
+ log_fatal("Impossible condition at %s:%d", MDL);
+ } else {
+ log_info("Bound to relay port *:%d",
+ (int) ntohs(relay_port));
+ }
+ }
+ info->rfdesc = relay_port_v6_socket;
+ info->wfdesc = relay_port_v6_socket;
+ relay_port_v6_socket_references++;
+ }
+#endif
+
if (req_multi)
if_register_multicast(info);
@@ -617,6 +654,16 @@ if_deregister6(struct interface_info *info) {
global_v6_socket_references--;
info->rfdesc = -1;
info->wfdesc = -1;
+#if defined(RELAY_PORT)
+ } else if (relay_port &&
+ (info->rfdesc == relay_port_v6_socket) &&
+ (info->wfdesc == relay_port_v6_socket) &&
+ (relay_port_v6_socket_references > 0)) {
+ /* Dereference the relay port v6 socket. */
+ relay_port_v6_socket_references--;
+ info->rfdesc = -1;
+ info->wfdesc = -1;
+#endif
} else {
log_fatal("Impossible condition at %s:%d", MDL);
}
@@ -633,12 +680,23 @@ if_deregister6(struct interface_info *info) {
}
}
- if (!no_global_v6_socket &&
- (global_v6_socket_references == 0)) {
- close(global_v6_socket);
- global_v6_socket = -1;
+ if (!no_global_v6_socket) {
+ if (global_v6_socket_references == 0) {
+ close(global_v6_socket);
+ global_v6_socket = -1;
- log_info("Unbound from *:%d", ntohs(local_port));
+ log_info("Unbound from *:%d",
+ (int) ntohs(local_port));
+ }
+#if defined(RELAY_PORT)
+ if (relay_port && (relay_port_v6_socket_references == 0)) {
+ close(relay_port_v6_socket);
+ relay_port_v6_socket = -1;
+
+ log_info("Unbound from relay port *:%d",
+ (int) ntohs(relay_port));
+ }
+#endif
}
}
#endif /* DHCPv6 */
diff --git a/common/tables.c b/common/tables.c
index 2350e803..b3d5ae66 100644
--- a/common/tables.c
+++ b/common/tables.c
@@ -557,12 +557,6 @@ static struct option dhcpv6_options[] = {
{ "solmax-rt", "L", &dhcpv6_universe, 82, 1 },
{ "inf-max-rt", "L", &dhcpv6_universe, 83, 1 },
#endif
-#if defined(RFC7710_OPTIONS)
- { "v6-captive-portal", "t", &dhcpv6_universe, 103, 1 },
-#endif
-#if defined(RFC6153_OPTIONS)
- { "ipv6-address-andsf", "6A", &dhcpv6_universe, 143, 1 },
-#endif
/* RFC7341 OPTIONS */
#if defined(RFC7341_OPTIONS)
@@ -570,6 +564,16 @@ static struct option dhcpv6_options[] = {
{ "dhcp4-o-dhcp6-server", "6A", &dhcpv6_universe, 88, 1 },
#endif
+#if defined(RFC7710_OPTIONS)
+ { "v6-captive-portal", "t", &dhcpv6_universe, 103, 1 },
+#endif
+
+ { "relay-source-port", "S", &dhcpv6_universe, 135, 1 },
+
+#if defined(RFC6153_OPTIONS)
+ { "ipv6-address-andsf", "6A", &dhcpv6_universe, 143, 1 },
+#endif
+
{ NULL, NULL, NULL, 0, 0 }
};
diff --git a/common/upf.c b/common/upf.c
index 1b49301e..9785879a 100644
--- a/common/upf.c
+++ b/common/upf.c
@@ -156,6 +156,9 @@ void if_deregister_send (info)
XXX Changes to the filter program may require changes to the constant
offsets used in if_register_send to patch the UPF program! XXX */
+#if defined(RELAY_PORT)
+#error "Relay port is not yet supported for UPF"
+#endif
void if_register_receive (info)
struct interface_info *info;