2
0
mirror of https://gitlab.isc.org/isc-projects/dhcp synced 2025-08-22 09:57:20 +00:00

Merged rt44535 (relay port)

This commit is contained in:
Francis Dupont 2017-12-23 01:18:23 +01:00
parent 0d6d300fec
commit 563f0b8aef
27 changed files with 685 additions and 57 deletions

View File

@ -312,6 +312,19 @@ dhcp-users@lists.isc.org.
when building with --enable-use-sockets and --enable-ipv4-pktinfo. when building with --enable-use-sockets and --enable-ipv4-pktinfo.
[ISC-Bugs #36118] [ISC-Bugs #36118]
(to be finalized before code freeze next year)
- Added experimental support for relay port (draft-ietf-dhc-relay-port-10.txt)
feature for DHCPv4, DHCPv6 and DHCPv4-over-DHCPv6. As the code points
were not yet assigned by IANA temporary (next free) values are used.
Relay port had be enabled at compile time via --enable-relay-port and
is fully backward compatible, i.e. works with previous implementations
of servers and relays, of course in this case using legacy ports.
A new --rp <relay-port> command line option specifies to dhcrelay
an alternate source port for upstream (i.e. toward the server) messages.
(update this)
Thanks to Naiming Shen and Enke Chen for submitting patches.
[ISC-Bugs #44535]
Changes since 4.3.6 (Bugs): Changes since 4.3.6 (Bugs):
- Corrected an issue where the server would return a client's previously - Corrected an issue where the server would return a client's previously

View File

@ -192,12 +192,51 @@ struct bpf_insn dhcp_bpf_filter [] = {
BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, 67, 0, 1), /* patch */ BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, 67, 0, 1), /* patch */
/* If we passed all the tests, ask for the whole packet. */ /* 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. */ /* 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) #if defined (DEC_FDDI)
struct bpf_insn *bpf_fddi_filter = NULL; struct bpf_insn *bpf_fddi_filter = NULL;
#endif #endif
@ -309,7 +348,19 @@ void if_register_receive (info)
/* Patch the server port into the BPF program... /* Patch the server port into the BPF program...
XXX changes to filter program may require changes XXX changes to filter program may require changes
to the insn number(s) used below! XXX */ 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) if (ioctl (info -> rfdesc, BIOCSETF, &p) < 0)
log_fatal ("Can't install packet filter program: %m"); log_fatal ("Can't install packet filter program: %m");

View File

@ -44,6 +44,7 @@ int interfaces_invalidated;
int quiet_interface_discovery; int quiet_interface_discovery;
u_int16_t local_port; u_int16_t local_port;
u_int16_t remote_port; u_int16_t remote_port;
u_int16_t relay_port = 0;
int dhcpv4_over_dhcpv6 = 0; int dhcpv4_over_dhcpv6 = 0;
int (*dhcp_interface_setup_hook) (struct interface_info *, struct iaddr *); int (*dhcp_interface_setup_hook) (struct interface_info *, struct iaddr *);
int (*dhcp_interface_discovery_hook) (struct interface_info *); int (*dhcp_interface_discovery_hook) (struct interface_info *);
@ -581,6 +582,10 @@ discover_interfaces(int state) {
int ir; int ir;
isc_result_t status; isc_result_t status;
int wifcount = 0; int wifcount = 0;
#ifdef RELAY_PORT
int updone = 0;
int downdone = 0;
#endif
static int setup_fallback = 0; static int setup_fallback = 0;
@ -946,9 +951,39 @@ discover_interfaces(int state) {
switch (local_family) { switch (local_family) {
#ifdef DHCPv6 #ifdef DHCPv6
case AF_INET6: 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, status = omapi_register_io_object((omapi_object_t *)tmp,
if_readsocket, if_readsocket,
0, got_one_v6, 0, 0); 0, got_one_v6, 0, 0);
#ifdef RELAY_PORT
if (UPSTREAM(tmp))
updone++;
else
downdone++;
#endif
break; break;
#endif /* DHCPv6 */ #endif /* DHCPv6 */
case AF_INET: case AF_INET:
@ -970,8 +1005,12 @@ discover_interfaces(int state) {
* dynamically adding and removing interfaces, but * dynamically adding and removing interfaces, but
* we're well beyond that point in terms of mess. * we're well beyond that point in terms of mess.
*/ */
if (((state == DISCOVER_SERVER) || (state == DISCOVER_RELAY)) && if (((state == DISCOVER_SERVER) || (state == DISCOVER_RELAY))
(local_family == AF_INET6)) && (local_family == AF_INET6)
#if defined(RELAY_PORT)
&& ((relay_port == 0) || (updone && downdone))
#endif
)
break; break;
#endif #endif
} /* for (tmp = interfaces; ... */ } /* for (tmp = interfaces; ... */

View File

@ -409,6 +409,10 @@ void if_deregister_send (info)
XXX Changes to the filter program may require changes to the constant XXX Changes to the filter program may require changes to the constant
offsets used in if_register_send to patch the NIT program! XXX */ 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) void if_register_receive (info)
struct interface_info *info; struct interface_info *info;
{ {

View File

@ -177,6 +177,11 @@ void if_deregister_send (info)
extern struct sock_filter dhcp_bpf_filter []; extern struct sock_filter dhcp_bpf_filter [];
extern int dhcp_bpf_filter_len; 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) #if defined (HAVE_TR_SUPPORT)
extern struct sock_filter dhcp_bpf_tr_filter []; extern struct sock_filter dhcp_bpf_tr_filter [];
extern int dhcp_bpf_tr_filter_len; 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... /* Patch the server port into the LPF program...
XXX changes to filter program may require changes XXX changes to filter program may require changes
to the insn number(s) used below! XXX */ 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, if (setsockopt (info -> rfdesc, SOL_SOCKET, SO_ATTACH_FILTER, &p,
sizeof p) < 0) { sizeof p) < 0) {

View File

@ -172,6 +172,10 @@ void if_deregister_send (info)
XXX Changes to the filter program may require changes to the constant XXX Changes to the filter program may require changes to the constant
offsets used in if_register_send to patch the NIT program! XXX */ 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) void if_register_receive (info)
struct interface_info *info; struct interface_info *info;
{ {

View File

@ -167,6 +167,12 @@ void assemble_udp_ip_header (interface, buf, bufix,
/* Fill out the UDP header */ /* Fill out the UDP header */
udp.uh_sport = local_port; /* XXX */ udp.uh_sport = local_port; /* XXX */
udp.uh_dport = 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); udp.uh_ulen = htons(sizeof(udp) + len);
memset (&udp.uh_sum, 0, sizeof udp.uh_sum); memset (&udp.uh_sum, 0, sizeof udp.uh_sum);
@ -296,7 +302,12 @@ decode_udp_ip_header(struct interface_info *interface,
return -1; return -1;
/* Is it to the port we're serving? */ /* 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) if (udp.uh_dport != local_port)
#endif
return -1; return -1;
#endif /* USERLAND_FILTER */ #endif /* USERLAND_FILTER */

View File

@ -55,14 +55,14 @@ void if_register_send (info)
/* Set up the address we're going to connect to. */ /* Set up the address we're going to connect to. */
name.sin_family = AF_INET; 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); name.sin_addr.s_addr = htonl (INADDR_BROADCAST);
memset (name.sin_zero, 0, sizeof (name.sin_zero)); memset (name.sin_zero, 0, sizeof (name.sin_zero));
/* List addresses on which we're listening. */ /* List addresses on which we're listening. */
if (!quiet_interface_discovery) if (!quiet_interface_discovery)
log_info ("Sending on %s, port %d", 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) if ((sock = socket (AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
log_fatal ("Can't create dhcp socket: %m"); log_fatal ("Can't create dhcp socket: %m");

View File

@ -65,6 +65,10 @@
static int no_global_v6_socket = 0; static int no_global_v6_socket = 0;
static unsigned int global_v6_socket_references = 0; static unsigned int global_v6_socket_references = 0;
static int global_v6_socket = -1; 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); static void if_register_multicast(struct interface_info *info);
#endif #endif
@ -157,6 +161,11 @@ if_register_socket(struct interface_info *info, int family,
addr6 = (struct sockaddr_in6 *)&name; addr6 = (struct sockaddr_in6 *)&name;
addr6->sin6_family = AF_INET6; addr6->sin6_family = AF_INET6;
addr6->sin6_port = local_port; 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 */ /* A server feature */
if (bind_local_address6) { if (bind_local_address6) {
memcpy(&addr6->sin6_addr, memcpy(&addr6->sin6_addr,
@ -187,7 +196,7 @@ if_register_socket(struct interface_info *info, int family,
default: default:
addr = (struct sockaddr_in *)&name; addr = (struct sockaddr_in *)&name;
addr->sin_family = AF_INET; addr->sin_family = AF_INET;
addr->sin_port = local_port; addr->sin_port = relay_port ? relay_port : local_port;
memcpy(&addr->sin_addr, memcpy(&addr->sin_addr,
&local_address, &local_address,
sizeof(addr->sin_addr)); 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); 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) { if (global_v6_socket_references == 0) {
global_v6_socket = if_register_socket(info, AF_INET6, global_v6_socket = if_register_socket(info, AF_INET6,
&req_multi, NULL); &req_multi, NULL);
@ -527,6 +540,30 @@ if_register6(struct interface_info *info, int do_multicast) {
info->wfdesc = global_v6_socket; info->wfdesc = global_v6_socket;
global_v6_socket_references++; 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 (req_multi)
if_register_multicast(info); if_register_multicast(info);
@ -617,6 +654,16 @@ if_deregister6(struct interface_info *info) {
global_v6_socket_references--; global_v6_socket_references--;
info->rfdesc = -1; info->rfdesc = -1;
info->wfdesc = -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 { } else {
log_fatal("Impossible condition at %s:%d", MDL); log_fatal("Impossible condition at %s:%d", MDL);
} }
@ -633,12 +680,23 @@ if_deregister6(struct interface_info *info) {
} }
} }
if (!no_global_v6_socket && if (!no_global_v6_socket) {
(global_v6_socket_references == 0)) { if (global_v6_socket_references == 0) {
close(global_v6_socket); close(global_v6_socket);
global_v6_socket = -1; 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 */ #endif /* DHCPv6 */

View File

@ -557,12 +557,6 @@ static struct option dhcpv6_options[] = {
{ "solmax-rt", "L", &dhcpv6_universe, 82, 1 }, { "solmax-rt", "L", &dhcpv6_universe, 82, 1 },
{ "inf-max-rt", "L", &dhcpv6_universe, 83, 1 }, { "inf-max-rt", "L", &dhcpv6_universe, 83, 1 },
#endif #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 */ /* RFC7341 OPTIONS */
#if defined(RFC7341_OPTIONS) #if defined(RFC7341_OPTIONS)
@ -570,6 +564,16 @@ static struct option dhcpv6_options[] = {
{ "dhcp4-o-dhcp6-server", "6A", &dhcpv6_universe, 88, 1 }, { "dhcp4-o-dhcp6-server", "6A", &dhcpv6_universe, 88, 1 },
#endif #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 } { NULL, NULL, NULL, 0, 0 }
}; };

View File

@ -156,6 +156,9 @@ void if_deregister_send (info)
XXX Changes to the filter program may require changes to the constant XXX Changes to the filter program may require changes to the constant
offsets used in if_register_send to patch the UPF program! XXX */ 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) void if_register_receive (info)
struct interface_info *info; struct interface_info *info;

25
configure vendored
View File

@ -768,6 +768,7 @@ enable_tracing
enable_delayed_ack enable_delayed_ack
enable_dhcpv6 enable_dhcpv6
enable_dhcpv4o6 enable_dhcpv4o6
enable_relay_port
enable_paranoia enable_paranoia
enable_early_chroot enable_early_chroot
enable_ipv4_pktinfo enable_ipv4_pktinfo
@ -1446,6 +1447,7 @@ Optional Features:
--enable-dhcpv6 enable support for DHCPv6 (default is yes) --enable-dhcpv6 enable support for DHCPv6 (default is yes)
--enable-dhcpv4o6 enable support for DHCPv4-over-DHCPv6 (default is --enable-dhcpv4o6 enable support for DHCPv4-over-DHCPv6 (default is
no) no)
--enable-relay-port enable support for relay port (default is no)
--enable-paranoia enable support for chroot/setuid (default is no) --enable-paranoia enable support for chroot/setuid (default is no)
--enable-early-chroot enable chrooting prior to configuration (default is --enable-early-chroot enable chrooting prior to configuration (default is
no) no)
@ -5487,6 +5489,19 @@ else
enable_dhcpv4o6="no" enable_dhcpv4o6="no"
fi fi
# Relay port (draft-ietf-dhc-relay-port-10.txt) optional compile-time feature.
# Check whether --enable-relay-port was given.
if test "${enable_relay_port+set}" = set; then :
enableval=$enable_relay_port;
fi
# Relay port is off by default (for now)
if test "$enable_relay_port" = "yes"; then
$as_echo "#define RELAY_PORT 1" >>confdefs.h
fi
# PARANOIA is off by default (until we can test it with all features) # PARANOIA is off by default (until we can test it with all features)
# Check whether --enable-paranoia was given. # Check whether --enable-paranoia was given.
if test "${enable_paranoia+set}" = set; then : if test "${enable_paranoia+set}" = set; then :
@ -6207,6 +6222,7 @@ fi
done done
# needed for linux/filter.h on old systems # needed for linux/filter.h on old systems
relay_port_supported="no"
ac_fn_c_check_header_compile "$LINENO" "linux/filter.h" "ac_cv_header_linux_filter_h" " ac_fn_c_check_header_compile "$LINENO" "linux/filter.h" "ac_cv_header_linux_filter_h" "
#ifdef HAVE_LINUX_TYPES_H #ifdef HAVE_LINUX_TYPES_H
#include <linux/types.h> #include <linux/types.h>
@ -6223,6 +6239,7 @@ then
$as_echo "#define HAVE_LPF 1" >>confdefs.h $as_echo "#define HAVE_LPF 1" >>confdefs.h
relay_port_supported="yes"
else else
ac_fn_c_check_header_mongrel "$LINENO" "sys/dlpi.h" "ac_cv_header_sys_dlpi_h" "$ac_includes_default" ac_fn_c_check_header_mongrel "$LINENO" "sys/dlpi.h" "ac_cv_header_sys_dlpi_h" "$ac_includes_default"
if test "x$ac_cv_header_sys_dlpi_h" = xyes; then : if test "x$ac_cv_header_sys_dlpi_h" = xyes; then :
@ -6247,10 +6264,17 @@ fi
$as_echo "#define HAVE_BPF 1" >>confdefs.h $as_echo "#define HAVE_BPF 1" >>confdefs.h
relay_port_supported="yes"
fi fi
fi fi
fi fi
if test "$enable_relay_port" = "yes"; then
if test "$relay_port_supported" != "yes"; then
as_fn_error $? "--enable-relay-port requires BPF or LPF" "$LINENO" 5
fi
fi
# SIOCGLIFCONF uses some transport structures. Trick is not all platforms # SIOCGLIFCONF uses some transport structures. Trick is not all platforms
# use the same structures. We like to use 'struct lifconf' and 'struct # use the same structures. We like to use 'struct lifconf' and 'struct
# lifreq', but we'll use these other structures if they're present. HPUX # lifreq', but we'll use these other structures if they're present. HPUX
@ -9014,6 +9038,7 @@ Features:
dhcpv6: $enable_dhcpv6 dhcpv6: $enable_dhcpv6
delayed-ack: $enable_delayed_ack delayed-ack: $enable_delayed_ack
dhcpv4o6: $enable_dhcpv4o6 dhcpv4o6: $enable_dhcpv4o6
relay-port: $enable_relay_port
Developer: Developer:
ATF unittests : $atf_path ATF unittests : $atf_path

View File

@ -177,6 +177,15 @@ else
enable_dhcpv4o6="no" enable_dhcpv4o6="no"
fi fi
# Relay port (draft-ietf-dhc-relay-port-10.txt) optional compile-time feature.
AC_ARG_ENABLE(relay-port,
AS_HELP_STRING([--enable-relay-port],[enable support for relay port (default is no)]))
# Relay port is off by default (for now)
if test "$enable_relay_port" = "yes"; then
AC_DEFINE([RELAY_PORT], [1],
[Define to 1 to include relay port support.])
fi
# PARANOIA is off by default (until we can test it with all features) # PARANOIA is off by default (until we can test it with all features)
AC_ARG_ENABLE(paranoia, AC_ARG_ENABLE(paranoia,
AS_HELP_STRING([--enable-paranoia],[enable support for chroot/setuid (default is no)])) AS_HELP_STRING([--enable-paranoia],[enable support for chroot/setuid (default is no)]))
@ -521,6 +530,7 @@ AC_CHECK_HEADERS(ifaddrs.h)
# figure out what IPv4 interface code to use # figure out what IPv4 interface code to use
AC_CHECK_HEADERS(linux/types.h) # needed for linux/filter.h on old systems AC_CHECK_HEADERS(linux/types.h) # needed for linux/filter.h on old systems
relay_port_supported="no"
AC_CHECK_HEADER(linux/filter.h, DO_LPF=1, , AC_CHECK_HEADER(linux/filter.h, DO_LPF=1, ,
[ [
#ifdef HAVE_LINUX_TYPES_H #ifdef HAVE_LINUX_TYPES_H
@ -531,6 +541,7 @@ if test -n "$DO_LPF"
then then
AC_DEFINE([HAVE_LPF], [1], AC_DEFINE([HAVE_LPF], [1],
[Define to 1 to use the Linux Packet Filter interface code.]) [Define to 1 to use the Linux Packet Filter interface code.])
relay_port_supported="yes"
else else
AC_CHECK_HEADER(sys/dlpi.h, DO_DLPI=1) AC_CHECK_HEADER(sys/dlpi.h, DO_DLPI=1)
if test -n "$DO_DLPI" if test -n "$DO_DLPI"
@ -544,10 +555,17 @@ else
AC_DEFINE([HAVE_BPF], [1], AC_DEFINE([HAVE_BPF], [1],
[Define to 1 to use the [Define to 1 to use the
Berkeley Packet Filter interface code.]) Berkeley Packet Filter interface code.])
relay_port_supported="yes"
fi fi
fi fi
fi fi
if test "$enable_relay_port" = "yes"; then
if test "$relay_port_supported" != "yes"; then
AC_MSG_ERROR([--enable-relay-port requires BPF or LPF])
fi
fi
# SIOCGLIFCONF uses some transport structures. Trick is not all platforms # SIOCGLIFCONF uses some transport structures. Trick is not all platforms
# use the same structures. We like to use 'struct lifconf' and 'struct # use the same structures. We like to use 'struct lifconf' and 'struct
# lifreq', but we'll use these other structures if they're present. HPUX # lifreq', but we'll use these other structures if they're present. HPUX
@ -1035,6 +1053,7 @@ Features:
dhcpv6: $enable_dhcpv6 dhcpv6: $enable_dhcpv6
delayed-ack: $enable_delayed_ack delayed-ack: $enable_delayed_ack
dhcpv4o6: $enable_dhcpv4o6 dhcpv4o6: $enable_dhcpv4o6
relay-port: $enable_relay_port
Developer: Developer:
ATF unittests : $atf_path ATF unittests : $atf_path

View File

@ -178,6 +178,15 @@ else
enable_dhcpv4o6="no" enable_dhcpv4o6="no"
fi fi
# Relay port (draft-ietf-dhc-relay-port-10.txt) optional compile-time feature.
AC_ARG_ENABLE(relay-port,
AS_HELP_STRING([--enable-relay-port],[enable support for relay port (default is no)]))
# Relay port is off by default (for now)
if test "$enable_relay_port" = "yes"; then
AC_DEFINE([RELAY_PORT], [1],
[Define to 1 to include relay port support.])
fi
# PARANOIA is off by default (until we can test it with all features) # PARANOIA is off by default (until we can test it with all features)
AC_ARG_ENABLE(paranoia, AC_ARG_ENABLE(paranoia,
AS_HELP_STRING([--enable-paranoia],[enable support for chroot/setuid (default is no)])) AS_HELP_STRING([--enable-paranoia],[enable support for chroot/setuid (default is no)]))
@ -522,6 +531,7 @@ AC_CHECK_HEADERS(ifaddrs.h)
# figure out what IPv4 interface code to use # figure out what IPv4 interface code to use
AC_CHECK_HEADERS(linux/types.h) # needed for linux/filter.h on old systems AC_CHECK_HEADERS(linux/types.h) # needed for linux/filter.h on old systems
relay_port_supported="no"
AC_CHECK_HEADER(linux/filter.h, DO_LPF=1, , AC_CHECK_HEADER(linux/filter.h, DO_LPF=1, ,
[ [
#ifdef HAVE_LINUX_TYPES_H #ifdef HAVE_LINUX_TYPES_H
@ -532,6 +542,7 @@ if test -n "$DO_LPF"
then then
AC_DEFINE([HAVE_LPF], [1], AC_DEFINE([HAVE_LPF], [1],
[Define to 1 to use the Linux Packet Filter interface code.]) [Define to 1 to use the Linux Packet Filter interface code.])
relay_port_supported="yes"
else else
AC_CHECK_HEADER(sys/dlpi.h, DO_DLPI=1) AC_CHECK_HEADER(sys/dlpi.h, DO_DLPI=1)
if test -n "$DO_DLPI" if test -n "$DO_DLPI"
@ -545,10 +556,17 @@ else
AC_DEFINE([HAVE_BPF], [1], AC_DEFINE([HAVE_BPF], [1],
[Define to 1 to use the [Define to 1 to use the
Berkeley Packet Filter interface code.]) Berkeley Packet Filter interface code.])
relay_port_supported="yes"
fi fi
fi fi
fi fi
if test "$enable_relay_port" = "yes"; then
if test "$relay_port_supported" != "yes"; then
AC_MSG_ERROR([--enable-relay-port requires BPF or LPF])
fi
fi
# SIOCGLIFCONF uses some transport structures. Trick is not all platforms # SIOCGLIFCONF uses some transport structures. Trick is not all platforms
# use the same structures. We like to use 'struct lifconf' and 'struct # use the same structures. We like to use 'struct lifconf' and 'struct
# lifreq', but we'll use these other structures if they're present. HPUX # lifreq', but we'll use these other structures if they're present. HPUX
@ -1040,6 +1058,7 @@ Features:
dhcpv6: $enable_dhcpv6 dhcpv6: $enable_dhcpv6
delayed-ack: $enable_delayed_ack delayed-ack: $enable_delayed_ack
dhcpv4o6: $enable_dhcpv4o6 dhcpv4o6: $enable_dhcpv4o6
relay-port: $enable_relay_port
Developer: Developer:
ATF unittests : $atf_path ATF unittests : $atf_path

View File

@ -183,6 +183,15 @@ else
enable_dhcpv4o6="no" enable_dhcpv4o6="no"
fi fi
# Relay port (draft-ietf-dhc-relay-port-10.txt) optional compile-time feature.
AC_ARG_ENABLE(relay-port,
AS_HELP_STRING([--enable-relay-port],[enable support for relay port (default is no)]))
# Relay port is off by default (for now)
if test "$enable_relay_port" = "yes"; then
AC_DEFINE([RELAY_PORT], [1],
[Define to 1 to include relay port support.])
fi
# PARANOIA is off by default (until we can test it with all features) # PARANOIA is off by default (until we can test it with all features)
AC_ARG_ENABLE(paranoia, AC_ARG_ENABLE(paranoia,
AS_HELP_STRING([--enable-paranoia],[enable support for chroot/setuid (default is no)])) AS_HELP_STRING([--enable-paranoia],[enable support for chroot/setuid (default is no)]))
@ -527,6 +536,7 @@ AC_CHECK_HEADERS(ifaddrs.h)
# figure out what IPv4 interface code to use # figure out what IPv4 interface code to use
AC_CHECK_HEADERS(linux/types.h) # needed for linux/filter.h on old systems AC_CHECK_HEADERS(linux/types.h) # needed for linux/filter.h on old systems
relay_port_supported="no"
AC_CHECK_HEADER(linux/filter.h, DO_LPF=1, , AC_CHECK_HEADER(linux/filter.h, DO_LPF=1, ,
[ [
#ifdef HAVE_LINUX_TYPES_H #ifdef HAVE_LINUX_TYPES_H
@ -537,6 +547,7 @@ if test -n "$DO_LPF"
then then
AC_DEFINE([HAVE_LPF], [1], AC_DEFINE([HAVE_LPF], [1],
[Define to 1 to use the Linux Packet Filter interface code.]) [Define to 1 to use the Linux Packet Filter interface code.])
relay_port_supported="yes"
else else
AC_CHECK_HEADER(sys/dlpi.h, DO_DLPI=1) AC_CHECK_HEADER(sys/dlpi.h, DO_DLPI=1)
if test -n "$DO_DLPI" if test -n "$DO_DLPI"
@ -550,10 +561,17 @@ else
AC_DEFINE([HAVE_BPF], [1], AC_DEFINE([HAVE_BPF], [1],
[Define to 1 to use the [Define to 1 to use the
Berkeley Packet Filter interface code.]) Berkeley Packet Filter interface code.])
relay_port_supported="yes"
fi fi
fi fi
fi fi
if test "$enable_relay_port" = "yes"; then
if test "$relay_port_supported" != "yes"; then
AC_MSG_ERROR([--enable-relay-port requires BPF or LPF])
fi
fi
# SIOCGLIFCONF uses some transport structures. Trick is not all platforms # SIOCGLIFCONF uses some transport structures. Trick is not all platforms
# use the same structures. We like to use 'struct lifconf' and 'struct # use the same structures. We like to use 'struct lifconf' and 'struct
# lifreq', but we'll use these other structures if they're present. HPUX # lifreq', but we'll use these other structures if they're present. HPUX
@ -1076,6 +1094,7 @@ Features:
dhcpv6: $enable_dhcpv6 dhcpv6: $enable_dhcpv6
delayed-ack: $enable_delayed_ack delayed-ack: $enable_delayed_ack
dhcpv4o6: $enable_dhcpv4o6 dhcpv4o6: $enable_dhcpv4o6
relay-port: $enable_relay_port
Developer: Developer:
ATF unittests : $atf_path ATF unittests : $atf_path

View File

@ -177,6 +177,15 @@ else
enable_dhcpv4o6="no" enable_dhcpv4o6="no"
fi fi
# Relay port (draft-ietf-dhc-relay-port-10.txt) optional compile-time feature.
AC_ARG_ENABLE(relay-port,
AS_HELP_STRING([--enable-relay-port],[enable support for relay port (default is no)]))
# Relay port is off by default (for now)
if test "$enable_relay_port" = "yes"; then
AC_DEFINE([RELAY_PORT], [1],
[Define to 1 to include relay port support.])
fi
# PARANOIA is off by default (until we can test it with all features) # PARANOIA is off by default (until we can test it with all features)
AC_ARG_ENABLE(paranoia, AC_ARG_ENABLE(paranoia,
AS_HELP_STRING([--enable-paranoia],[enable support for chroot/setuid (default is no)])) AS_HELP_STRING([--enable-paranoia],[enable support for chroot/setuid (default is no)]))
@ -521,6 +530,7 @@ AC_CHECK_HEADERS(ifaddrs.h)
# figure out what IPv4 interface code to use # figure out what IPv4 interface code to use
AC_CHECK_HEADERS(linux/types.h) # needed for linux/filter.h on old systems AC_CHECK_HEADERS(linux/types.h) # needed for linux/filter.h on old systems
relay_port_supported="no"
AC_CHECK_HEADER(linux/filter.h, DO_LPF=1, , AC_CHECK_HEADER(linux/filter.h, DO_LPF=1, ,
[ [
#ifdef HAVE_LINUX_TYPES_H #ifdef HAVE_LINUX_TYPES_H
@ -531,6 +541,7 @@ if test -n "$DO_LPF"
then then
AC_DEFINE([HAVE_LPF], [1], AC_DEFINE([HAVE_LPF], [1],
[Define to 1 to use the Linux Packet Filter interface code.]) [Define to 1 to use the Linux Packet Filter interface code.])
relay_port_supported="yes"
else else
AC_CHECK_HEADER(sys/dlpi.h, DO_DLPI=1) AC_CHECK_HEADER(sys/dlpi.h, DO_DLPI=1)
if test -n "$DO_DLPI" if test -n "$DO_DLPI"
@ -544,10 +555,17 @@ else
AC_DEFINE([HAVE_BPF], [1], AC_DEFINE([HAVE_BPF], [1],
[Define to 1 to use the [Define to 1 to use the
Berkeley Packet Filter interface code.]) Berkeley Packet Filter interface code.])
relay_port_supported="yes"
fi fi
fi fi
fi fi
if test "$enable_relay_port" = "yes"; then
if test "$relay_port_supported" != "yes"; then
AC_MSG_ERROR([--enable-relay-port requires BPF or LPF])
fi
fi
# SIOCGLIFCONF uses some transport structures. Trick is not all platforms # SIOCGLIFCONF uses some transport structures. Trick is not all platforms
# use the same structures. We like to use 'struct lifconf' and 'struct # use the same structures. We like to use 'struct lifconf' and 'struct
# lifreq', but we'll use these other structures if they're present. HPUX # lifreq', but we'll use these other structures if they're present. HPUX
@ -1035,6 +1053,7 @@ Features:
dhcpv6: $enable_dhcpv6 dhcpv6: $enable_dhcpv6
delayed-ack: $enable_delayed_ack delayed-ack: $enable_delayed_ack
dhcpv4o6: $enable_dhcpv4o6 dhcpv4o6: $enable_dhcpv4o6
relay-port: $enable_relay_port
Developer: Developer:
ATF unittests : $atf_path ATF unittests : $atf_path

View File

@ -219,3 +219,10 @@ to start the server.
Finally note in the configuration file the use of the shared-network to Finally note in the configuration file the use of the shared-network to
connect the DHCPv4 and DHCPv6 subnets. connect the DHCPv4 and DHCPv6 subnets.
USE WITH DHCPv6 RELAY(s)
If the DHCPv6 infrastructure uses one (or more) relay because the client
and the server are not on the same link the best choice is to put the
first (closest to client) relay address in the dhcp4-o-dhcp6-server
option so the same path between the DHCPv6 client part and server part
will be used for DHCPv6 and DHCPv4-over-DHCPv6 traffic.

View File

@ -157,6 +157,9 @@
/* Define to any value to include Ari's PARANOIA patch. */ /* Define to any value to include Ari's PARANOIA patch. */
#undef PARANOIA #undef PARANOIA
/* Define to 1 to include relay port support. */
#undef RELAY_PORT
/* The size of `struct iaddr *', as computed by sizeof. */ /* The size of `struct iaddr *', as computed by sizeof. */
#undef SIZEOF_STRUCT_IADDR_P #undef SIZEOF_STRUCT_IADDR_P

View File

@ -183,6 +183,8 @@ struct dhcp_packet {
#define RAI_REMOTE_ID 2 #define RAI_REMOTE_ID 2
#define RAI_AGENT_ID 3 #define RAI_AGENT_ID 3
#define RAI_LINK_SELECT 5 #define RAI_LINK_SELECT 5
/* not yet assigned but next free value */
#define RAI_RELAY_PORT 19
/* FQDN suboptions: */ /* FQDN suboptions: */
#define FQDN_NO_CLIENT_UPDATE 1 #define FQDN_NO_CLIENT_UPDATE 1

View File

@ -115,6 +115,8 @@
#define D6O_V6_PCP_SERVER 86 /* RFC7291 */ #define D6O_V6_PCP_SERVER 86 /* RFC7291 */
#define D6O_DHCPV4_MSG 87 /* RFC7341 */ #define D6O_DHCPV4_MSG 87 /* RFC7341 */
#define D6O_DHCP4_O_DHCP6_SERVER 88 /* RFC7341 */ #define D6O_DHCP4_O_DHCP6_SERVER 88 /* RFC7341 */
/* not yet assigned but next free value */
#define D6O_RELAY_SOURCE_PORT 135 /* I-D */
/* /*
* Status Codes, from RFC 3315 section 24.4, and RFC 3633, 5007, 5460. * Status Codes, from RFC 3315 section 24.4, and RFC 3633, 5007, 5460.

View File

@ -469,9 +469,12 @@ struct packet {
*/ */
isc_boolean_t unicast; isc_boolean_t unicast;
/* Propogates server value SV_ECHO_CLIENT_ID so it is available /* Propagates server value SV_ECHO_CLIENT_ID so it is available
* in cons_options() */ * in cons_options() */
int sv_echo_client_id; int sv_echo_client_id;
/* Relay port check */
isc_boolean_t relay_source_port;
}; };
/* /*
@ -2440,6 +2443,8 @@ void eval_network_statements(struct option_state **options,
struct packet *packet, struct packet *packet,
struct group *network_group); struct group *network_group);
u_int16_t dhcp_check_relayport(struct packet *packet);
/* dhcpleasequery.c */ /* dhcpleasequery.c */
void dhcpleasequery (struct packet *, int); void dhcpleasequery (struct packet *, int);
void dhcpv6_leasequery (struct data_string *, struct packet *); void dhcpv6_leasequery (struct data_string *, struct packet *);
@ -2833,6 +2838,7 @@ extern int bind_local_address6;
extern u_int16_t local_port; extern u_int16_t local_port;
extern u_int16_t remote_port; extern u_int16_t remote_port;
extern u_int16_t relay_port;
extern int dhcpv4_over_dhcpv6; extern int dhcpv4_over_dhcpv6;
extern int (*dhcp_interface_setup_hook) (struct interface_info *, extern int (*dhcp_interface_setup_hook) (struct interface_info *,
struct iaddr *); struct iaddr *);

View File

@ -43,6 +43,9 @@ dhcrelay - Dynamic Host Configuration Protocol Relay Agent
[ [
.B -p .B -p
.I port .I port
|
.B -rp
.I relay-port
] ]
[ [
.B -c .B -c
@ -112,6 +115,9 @@ dhcrelay - Dynamic Host Configuration Protocol Relay Agent
[ [
.B -p .B -p
.I port .I port
|
.B -rp
.I relay-port
] ]
[ [
.B -c .B -c
@ -174,7 +180,7 @@ the command line, to which DHCP/BOOTP queries should be relayed.
.PP .PP
\fIOptions available for both DHCPv4 and DHCPv6:\fR \fIOptions available for both DHCPv4 and DHCPv6:\fR
.TP .TP
-c COUNT -c \fIcount\fR
Maximum hop count. When forwarding packets, dhcrelay discards packets Maximum hop count. When forwarding packets, dhcrelay discards packets
which have reached a hop count of COUNT. Default is 10. Maximum is 255. which have reached a hop count of COUNT. Default is 10. Maximum is 255.
.TP .TP
@ -182,9 +188,17 @@ which have reached a hop count of COUNT. Default is 10. Maximum is 255.
Force dhcrelay to run as a foreground process. Useful when running Force dhcrelay to run as a foreground process. Useful when running
dhcrelay under a debugger, or running out of inittab on System V systems. dhcrelay under a debugger, or running out of inittab on System V systems.
.TP .TP
-p PORT -p \fIport\fR
Listen and transmit on port PORT. This is mostly useful for debugging Listen and transmit on port PORT. This is mostly useful for debugging
purposes. Default is port 67 for DHCPv4/BOOTP, or port 547 for DHCPv6. purposes. Default is port 67 for DHCPv4/BOOTP, or port 547 for DHCPv6.
Incompatible with \fB-rp\fR.
.TP
-rp \fIrelay-port\fR
Alternative source port for upstream (i.e toward the server) messages
with DHCPv4 RAI relay-port sub-option or DHCPv6 relay-source-port
option. Relay port support is only available if the code was compiled
with (./configure --enable-relay-port) and requires LPF or BPF link
layer access.
.TP .TP
-q -q
Quiet mode. Prevents dhcrelay6 from printing its network configuration Quiet mode. Prevents dhcrelay6 from printing its network configuration
@ -209,7 +223,7 @@ be the printable name of the interface on which the client request was
received. The client supports inclusion of a Remote ID suboption as well, received. The client supports inclusion of a Remote ID suboption as well,
but this is not used by default. but this is not used by default.
.TP .TP
-A LENGTH -A \fIlength\fR
Specify the maximum packet size to send to a DHCPv4/BOOTP server. This Specify the maximum packet size to send to a DHCPv4/BOOTP server. This
might be done to allow sufficient space for addition of relay agent might be done to allow sufficient space for addition of relay agent
options while still fitting into the Ethernet MTU size. options while still fitting into the Ethernet MTU size.

View File

@ -152,8 +152,30 @@ static const char url[] =
char *progname; char *progname;
#ifdef DHCPv6 #ifdef DHCPv6
#ifdef RELAY_PORT
#define DHCRELAY_USAGE \ #define DHCRELAY_USAGE \
"Usage: %s [-4] [-d] [-q] [-a] [-D]\n"\ "Usage: %s [-4] [-d] [-q] [-a] [-D]\n" \
" [-A <length>] [-c <hops>]\n" \
" [-p <port> | -rp <relay-port>]\n" \
" [-pf <pid-file>] [--no-pid]\n"\
" [-m append|replace|forward|discard]\n" \
" [-i interface0 [ ... -i interfaceN]\n" \
" [-iu interface0 [ ... -iu interfaceN]\n" \
" [-id interface0 [ ... -id interfaceN]\n" \
" [-U interface]\n" \
" server0 [ ... serverN]\n\n" \
" %s -6 [-d] [-q] [-I] [-c <hops>]\n" \
" [-p <port> | -rp <relay-port>]\n" \
" [-pf <pid-file>] [--no-pid]\n" \
" [-s <subscriber-id>]\n" \
" -l lower0 [ ... -l lowerN]\n" \
" -u upper0 [ ... -u upperN]\n" \
" lower (client link): [address%%]interface[#index]\n" \
" upper (server link): [address%%]interface\n\n" \
" %s {--version|--help|-h}"
#else
#define DHCRELAY_USAGE \
"Usage: %s [-4] [-d] [-q] [-a] [-D]\n" \
" [-A <length>] [-c <hops>] [-p <port>]\n" \ " [-A <length>] [-c <hops>] [-p <port>]\n" \
" [-pf <pid-file>] [--no-pid]\n"\ " [-pf <pid-file>] [--no-pid]\n"\
" [-m append|replace|forward|discard]\n" \ " [-m append|replace|forward|discard]\n" \
@ -170,6 +192,20 @@ char *progname;
" lower (client link): [address%%]interface[#index]\n" \ " lower (client link): [address%%]interface[#index]\n" \
" upper (server link): [address%%]interface\n\n" \ " upper (server link): [address%%]interface\n\n" \
" %s {--version|--help|-h}" " %s {--version|--help|-h}"
#endif
#else /* !DHCPv6 */
#ifdef RELAY_PORT
#define DHCRELAY_USAGE \
"Usage: %s [-d] [-q] [-a] [-D] [-A <length>] [-c <hops>]\n" \
" [-p <port> | -rp <relay-port>]\n" \
" [-pf <pid-file>] [--no-pid]\n" \
" [-m append|replace|forward|discard]\n" \
" [-i interface0 [ ... -i interfaceN]\n" \
" [-iu interface0 [ ... -iu interfaceN]\n" \
" [-id interface0 [ ... -id interfaceN]\n" \
" [-U interface]\n" \
" server0 [ ... serverN]\n\n" \
" %s {--version|--help|-h}"
#else #else
#define DHCRELAY_USAGE \ #define DHCRELAY_USAGE \
"Usage: %s [-d] [-q] [-a] [-D] [-A <length>] [-c <hops>] [-p <port>]\n" \ "Usage: %s [-d] [-q] [-a] [-D] [-A <length>] [-c <hops>] [-p <port>]\n" \
@ -182,6 +218,7 @@ char *progname;
" server0 [ ... serverN]\n\n" \ " server0 [ ... serverN]\n\n" \
" %s {--version|--help|-h}" " %s {--version|--help|-h}"
#endif #endif
#endif
/*! /*!
* *
@ -199,6 +236,12 @@ char *progname;
* \return Nothing * \return Nothing
*/ */
static const char use_noarg[] = "No argument for command: %s"; static const char use_noarg[] = "No argument for command: %s";
#ifdef RELAY_PORT
static const char use_port_defined[] = "Port already set, %s inappropriate";
#if !defined (USE_BPF_RECEIVE) && !defined (USE_LPF_RECEIVE)
static const char bpf_sock_support[] = "Only LPF and BPF are supported: %s";
#endif
#endif
#ifdef DHCPv6 #ifdef DHCPv6
static const char use_badproto[] = "Protocol already set, %s inappropriate"; static const char use_badproto[] = "Protocol already set, %s inappropriate";
static const char use_v4command[] = "Command not used for DHCPv6: %s"; static const char use_v4command[] = "Command not used for DHCPv6: %s";
@ -236,6 +279,9 @@ main(int argc, char **argv) {
int quiet = 0; int quiet = 0;
int fd; int fd;
int i; int i;
#ifdef RELAY_PORT
int port_defined = 0;
#endif
#ifdef DHCPv6 #ifdef DHCPv6
struct stream_list *sl = NULL; struct stream_list *sl = NULL;
int local_family_set = 0; int local_family_set = 0;
@ -349,9 +395,26 @@ main(int argc, char **argv) {
} else if (!strcmp(argv[i], "-p")) { } else if (!strcmp(argv[i], "-p")) {
if (++i == argc) if (++i == argc)
usage(use_noarg, argv[i-1]); usage(use_noarg, argv[i-1]);
#ifdef RELAY_PORT
if (port_defined)
usage(use_port_defined, argv[i-1]);
port_defined = 1;
#endif
local_port = validate_port(argv[i]); local_port = validate_port(argv[i]);
log_debug("binding to user-specified port %d", log_debug("binding to user-specified port %d",
ntohs(local_port)); ntohs(local_port));
#ifdef RELAY_PORT
} else if (!strcmp(argv[i], "-rp")) {
if (++i == argc)
usage(use_noarg, argv[i-1]);
if (port_defined)
usage(use_port_defined, argv[i-1]);
port_defined = 1;
relay_port = validate_port(argv[i]);
log_debug("binding to user-specified relay port %d",
ntohs(relay_port));
add_agent_options = 1;
#endif
} else if (!strcmp(argv[i], "-c")) { } else if (!strcmp(argv[i], "-c")) {
int hcount; int hcount;
if (++i == argc) if (++i == argc)
@ -572,6 +635,12 @@ main(int argc, char **argv) {
} }
} }
#if defined(RELAY_PORT) && \
!defined (USE_BPF_RECEIVE) && !defined (USE_LPF_RECEIVE)
if (relay_port && (local_family == AF_INET))
usage(bpf_sock_support, "-rp");
#endif
/* /*
* If the user didn't specify a pid file directly * If the user didn't specify a pid file directly
* find one from environment variables or defaults * find one from environment variables or defaults
@ -1259,6 +1328,12 @@ add_relay_agent_options(struct interface_info *ip, struct dhcp_packet *packet,
optlen += 6; optlen += 6;
} }
#ifdef RELAY_PORT
if (relay_port) {
optlen += 2;
}
#endif
/* We do not support relay option fragmenting(multiple options to /* We do not support relay option fragmenting(multiple options to
* support an option data exceeding 255 bytes). * support an option data exceeding 255 bytes).
*/ */
@ -1303,6 +1378,14 @@ add_relay_agent_options(struct interface_info *ip, struct dhcp_packet *packet,
log_debug ("Adding link selection suboption" log_debug ("Adding link selection suboption"
" with addr: %s", inet_ntoa(giaddr)); " with addr: %s", inet_ntoa(giaddr));
} }
#ifdef RELAY_PORT
/* draft-ietf-dhc-relay-port-10.txt section 5.1 */
if (relay_port) {
*sp++ = RAI_RELAY_PORT;
*sp++ = 0u;
}
#endif
} else { } else {
++agent_option_errors; ++agent_option_errors;
log_error("No room in packet (used %d of %d) " log_error("No room in packet (used %d of %d) "
@ -1548,6 +1631,9 @@ setup_streams(void) {
static const int required_forw_opts[] = { static const int required_forw_opts[] = {
D6O_INTERFACE_ID, D6O_INTERFACE_ID,
D6O_SUBSCRIBER_ID, D6O_SUBSCRIBER_ID,
#if defined(RELAY_PORT)
D6O_RELAY_SOURCE_PORT,
#endif
D6O_RELAY_MSG, D6O_RELAY_MSG,
0 0
}; };
@ -1562,6 +1648,7 @@ process_up6(struct packet *packet, struct stream_list *dp) {
struct dhcpv6_relay_packet *relay; struct dhcpv6_relay_packet *relay;
struct option_state *opts; struct option_state *opts;
struct stream_list *up; struct stream_list *up;
u_int16_t relay_client_port = 0;
/* Check if the message should be relayed to the server. */ /* Check if the message should be relayed to the server. */
switch (packet->dhcpv6_msg_type) { switch (packet->dhcpv6_msg_type) {
@ -1622,6 +1709,10 @@ process_up6(struct packet *packet, struct stream_list *dp) {
} }
memset(&relay->link_address, 0, 16); memset(&relay->link_address, 0, 16);
} }
if (packet->client_port != htons(547)) {
relay_client_port = packet->client_port;
}
} else { } else {
relay->hop_count = 0; relay->hop_count = 0;
if (!dp) if (!dp)
@ -1674,6 +1765,30 @@ process_up6(struct packet *packet, struct stream_list *dp) {
} }
#if defined(RELAY_PORT)
/*
* If we use a non-547 UDP source port or if we have received
* from a downstream relay agent uses a non-547 port, we need
* to include the RELAY-SOURCE-PORT option. The "Downstream
* UDP Port" field value in the option allow us to send
* relay-reply message back to the downstream relay agent
* with the correct UDP source port.
*/
if (relay_port || relay_client_port) {
if (!save_option_buffer(&dhcpv6_universe, opts, NULL,
(unsigned char *) &relay_client_port,
sizeof(u_int16_t),
D6O_RELAY_SOURCE_PORT, 0)) {
log_error("Can't save relay-source-port.");
option_state_dereference(&opts, MDL);
return;
}
}
#else
/* Avoid unused but set warning, */
(void)(relay_client_port);
#endif
/* Add the relay-msg carrying the packet. */ /* Add the relay-msg carrying the packet. */
if (!save_option_buffer(&dhcpv6_universe, opts, if (!save_option_buffer(&dhcpv6_universe, opts,
NULL, (unsigned char *) packet->raw, NULL, (unsigned char *) packet->raw,
@ -1708,6 +1823,9 @@ process_down6(struct packet *packet) {
struct data_string relay_msg; struct data_string relay_msg;
const struct dhcpv6_packet *msg; const struct dhcpv6_packet *msg;
struct data_string if_id; struct data_string if_id;
#if defined(RELAY_PORT)
struct data_string down_port;
#endif
struct sockaddr_in6 to; struct sockaddr_in6 to;
struct iaddr peer; struct iaddr peer;
@ -1729,6 +1847,9 @@ process_down6(struct packet *packet) {
/* Inits. */ /* Inits. */
memset(&relay_msg, 0, sizeof(relay_msg)); memset(&relay_msg, 0, sizeof(relay_msg));
memset(&if_id, 0, sizeof(if_id)); memset(&if_id, 0, sizeof(if_id));
#if defined(RELAY_PORT)
memset(&down_port, 0, sizeof(down_port));
#endif
memset(&to, 0, sizeof(to)); memset(&to, 0, sizeof(to));
to.sin6_family = AF_INET6; to.sin6_family = AF_INET6;
#ifdef HAVE_SA_LEN #ifdef HAVE_SA_LEN
@ -1799,6 +1920,37 @@ process_down6(struct packet *packet) {
/* Relay-Reply of for another relay, not a client. */ /* Relay-Reply of for another relay, not a client. */
case DHCPV6_RELAY_REPL: case DHCPV6_RELAY_REPL:
to.sin6_port = local_port; to.sin6_port = local_port;
#if defined(RELAY_PORT)
oc = lookup_option(&dhcpv6_universe, packet->options,
D6O_RELAY_SOURCE_PORT);
if (oc != NULL) {
u_int16_t down_relay_port;
memset(&down_port, 0, sizeof(down_port));
if (!evaluate_option_cache(&down_port, packet, NULL,
NULL, packet->options, NULL,
&global_scope, oc, MDL) ||
(down_port.len != sizeof(u_int16_t))) {
log_info("Can't evaluate down "
"relay-source-port.");
goto cleanup;
}
memcpy(&down_relay_port, down_port.data,
sizeof(u_int16_t));
/*
* If the down_relay_port value is non-zero,
* that means our downstream relay agent uses
* a non-547 UDP source port sending
* relay-forw message to us. We need to use
* the same UDP port sending reply back.
*/
if (down_relay_port) {
to.sin6_port = down_relay_port;
}
}
#endif
/* Fall into: */ /* Fall into: */
case DHCPV6_ADVERTISE: case DHCPV6_ADVERTISE:

View File

@ -1063,6 +1063,20 @@ void dhcpdecline (packet, ms_nulltp)
lease_dereference (&lease, MDL); lease_dereference (&lease, MDL);
} }
#if defined(RELAY_PORT)
u_int16_t dhcp_check_relayport(packet)
struct packet *packet;
{
if (lookup_option(&agent_universe,
packet->options,
RAI_RELAY_PORT) != NULL) {
return (packet->client_port);
}
return (0);
}
#endif
void dhcpinform (packet, ms_nulltp) void dhcpinform (packet, ms_nulltp)
struct packet *packet; struct packet *packet;
int ms_nulltp; int ms_nulltp;
@ -1084,6 +1098,7 @@ void dhcpinform (packet, ms_nulltp)
struct interface_info *interface; struct interface_info *interface;
int result, h_m_client_ip = 0; int result, h_m_client_ip = 0;
struct host_decl *host = NULL, *hp = NULL, *h; struct host_decl *host = NULL, *hp = NULL, *h;
u_int16_t relay_port = 0;
#if defined (DEBUG_INFORM_HOST) #if defined (DEBUG_INFORM_HOST)
int h_w_fixed_addr = 0; int h_w_fixed_addr = 0;
#endif #endif
@ -1146,6 +1161,10 @@ void dhcpinform (packet, ms_nulltp)
return; return;
} }
#if defined(RELAY_PORT)
relay_port = dhcp_check_relayport(packet);
#endif
/* Find the subnet that the client is on. /* Find the subnet that the client is on.
* CC: Do the link selection / subnet selection * CC: Do the link selection / subnet selection
*/ */
@ -1696,7 +1715,7 @@ void dhcpinform (packet, ms_nulltp)
*/ */
if (!raw.ciaddr.s_addr && gip.len) { if (!raw.ciaddr.s_addr && gip.len) {
memcpy(&to.sin_addr, gip.iabuf, 4); memcpy(&to.sin_addr, gip.iabuf, 4);
to.sin_port = local_port; to.sin_port = relay_port ? relay_port : local_port;
raw.flags |= htons(BOOTP_BROADCAST); raw.flags |= htons(BOOTP_BROADCAST);
} else { } else {
gip.len = 0; gip.len = 0;
@ -1753,6 +1772,7 @@ void nak_lease (packet, cip, network_group)
unsigned char nak = DHCPNAK; unsigned char nak = DHCPNAK;
struct packet outgoing; struct packet outgoing;
unsigned i; unsigned i;
u_int16_t relay_port = 0;
struct option_state *options = (struct option_state *)0; struct option_state *options = (struct option_state *)0;
struct option_cache *oc = (struct option_cache *)0; struct option_cache *oc = (struct option_cache *)0;
struct option_state *eval_options = NULL; struct option_state *eval_options = NULL;
@ -1781,6 +1801,10 @@ void nak_lease (packet, cip, network_group)
save_option (&dhcp_universe, options, oc); save_option (&dhcp_universe, options, oc);
option_cache_dereference (&oc, MDL); option_cache_dereference (&oc, MDL);
#if defined(RELAY_PORT)
relay_port = dhcp_check_relayport(packet);
#endif
/* Set DHCP_MESSAGE to whatever the message is */ /* Set DHCP_MESSAGE to whatever the message is */
if (!option_cache_allocate (&oc, MDL)) { if (!option_cache_allocate (&oc, MDL)) {
log_error ("No memory for DHCPNAK message type."); log_error ("No memory for DHCPNAK message type.");
@ -1929,7 +1953,7 @@ void nak_lease (packet, cip, network_group)
if (raw.giaddr.s_addr) { if (raw.giaddr.s_addr) {
to.sin_addr = raw.giaddr; to.sin_addr = raw.giaddr;
if (raw.giaddr.s_addr != htonl (INADDR_LOOPBACK)) if (raw.giaddr.s_addr != htonl (INADDR_LOOPBACK))
to.sin_port = local_port; to.sin_port = relay_port ? relay_port : local_port;
else else
to.sin_port = remote_port; /* for testing. */ to.sin_port = remote_port; /* for testing. */
@ -3752,6 +3776,7 @@ void dhcp_reply (lease)
int result; int result;
struct lease_state *state = lease -> state; struct lease_state *state = lease -> state;
int nulltp, bootpp, unicastp = 1; int nulltp, bootpp, unicastp = 1;
u_int16_t relay_port = 0;
struct data_string d1; struct data_string d1;
const char *s; const char *s;
@ -3921,11 +3946,15 @@ void dhcp_reply (lease)
#endif #endif
memset (to.sin_zero, 0, sizeof to.sin_zero); memset (to.sin_zero, 0, sizeof to.sin_zero);
#if defined(RELAY_PORT)
relay_port = dhcp_check_relayport(state->packet);
#endif
/* If this was gatewayed, send it back to the gateway... */ /* If this was gatewayed, send it back to the gateway... */
if (raw.giaddr.s_addr) { if (raw.giaddr.s_addr) {
to.sin_addr = raw.giaddr; to.sin_addr = raw.giaddr;
if (raw.giaddr.s_addr != htonl (INADDR_LOOPBACK)) if (raw.giaddr.s_addr != htonl (INADDR_LOOPBACK))
to.sin_port = local_port; to.sin_port = relay_port ? relay_port : local_port;
else else
to.sin_port = remote_port; /* For debugging. */ to.sin_port = remote_port; /* For debugging. */

View File

@ -152,6 +152,7 @@ dhcpleasequery(struct packet *packet, int ms_nulltp) {
u_int32_t time_rebinding; u_int32_t time_rebinding;
u_int32_t time_expiry; u_int32_t time_expiry;
u_int32_t client_last_transaction_time; u_int32_t client_last_transaction_time;
u_int16_t relay_port = 0;
struct sockaddr_in to; struct sockaddr_in to;
struct in_addr siaddr; struct in_addr siaddr;
struct data_string prl; struct data_string prl;
@ -660,12 +661,16 @@ dhcpleasequery(struct packet *packet, int ms_nulltp) {
#endif #endif
memset(to.sin_zero, 0, sizeof(to.sin_zero)); memset(to.sin_zero, 0, sizeof(to.sin_zero));
#if defined(RELAY_PORT)
relay_port = dhcp_check_relayport(packet);
#endif
/* /*
* Leasequery packets are be sent to the gateway address. * Leasequery packets are be sent to the gateway address.
*/ */
to.sin_addr = packet->raw->giaddr; to.sin_addr = packet->raw->giaddr;
if (packet->raw->giaddr.s_addr != htonl(INADDR_LOOPBACK)) { if (packet->raw->giaddr.s_addr != htonl(INADDR_LOOPBACK)) {
to.sin_port = local_port; to.sin_port = relay_port ? relay_port : local_port;
} else { } else {
to.sin_port = remote_port; /* XXXSK: For debugging. */ to.sin_port = remote_port; /* XXXSK: For debugging. */
} }

View File

@ -27,6 +27,14 @@ static void send_dhcpv4_response(struct data_string *raw);
static void recv_dhcpv4_query(struct data_string *raw); static void recv_dhcpv4_query(struct data_string *raw);
static void dhcp4o6_dhcpv4_query(struct data_string *reply_ret, static void dhcp4o6_dhcpv4_query(struct data_string *reply_ret,
struct packet *packet); struct packet *packet);
struct udp_data4o6 {
u_int16_t src_port;
u_int8_t rsp_opt_exist;
u_int8_t reserved;
};
static int offset_data4o6 = 36; /* 16+16+4 */
#endif #endif
/* /*
@ -211,7 +219,7 @@ isc_result_t dhcpv4o6_handler(omapi_object_t *h) {
cc = recv(dhcp4o6_fd, buf, sizeof(buf), 0); cc = recv(dhcp4o6_fd, buf, sizeof(buf), 0);
if (cc < DHCP_FIXED_NON_UDP + 32) if (cc < DHCP_FIXED_NON_UDP + offset_data4o6)
return ISC_R_UNEXPECTED; return ISC_R_UNEXPECTED;
memset(&raw, 0, sizeof(raw)); memset(&raw, 0, sizeof(raw));
if (!buffer_allocate(&raw.buffer, cc, MDL)) { if (!buffer_allocate(&raw.buffer, cc, MDL)) {
@ -237,7 +245,7 @@ isc_result_t dhcpv4o6_handler(omapi_object_t *h) {
* \brief Send the DHCPv4-response back to the DHCPv6 side * \brief Send the DHCPv4-response back to the DHCPv6 side
* (DHCPv6 server function) * (DHCPv6 server function)
* *
* Format: interface:16 + address:16 + DHCPv6 DHCPv4-response message * Format: interface:16 + address:16 + udp:4 + DHCPv6 DHCPv4-response message
* *
* \param raw the IPC message content * \param raw the IPC message content
*/ */
@ -246,6 +254,7 @@ static void send_dhcpv4_response(struct data_string *raw) {
char name[16 + 1]; char name[16 + 1];
struct sockaddr_in6 to_addr; struct sockaddr_in6 to_addr;
char pbuf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; char pbuf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
struct udp_data4o6 udp_data;
int send_ret; int send_ret;
memset(name, 0, sizeof(name)); memset(name, 0, sizeof(name));
@ -263,26 +272,32 @@ static void send_dhcpv4_response(struct data_string *raw) {
memset(&to_addr, 0, sizeof(to_addr)); memset(&to_addr, 0, sizeof(to_addr));
to_addr.sin6_family = AF_INET6; to_addr.sin6_family = AF_INET6;
memcpy(&to_addr.sin6_addr, raw->data + 16, 16); memcpy(&to_addr.sin6_addr, raw->data + 16, 16);
if ((raw->data[32] == DHCPV6_RELAY_FORW) || memset(&udp_data, 0, sizeof(udp_data));
(raw->data[32] == DHCPV6_RELAY_REPL)) { memcpy(&udp_data, raw->data + 32, 4);
to_addr.sin6_port = local_port; if ((raw->data[36] == DHCPV6_RELAY_FORW) ||
(raw->data[36] == DHCPV6_RELAY_REPL)) {
if (udp_data.rsp_opt_exist) {
to_addr.sin6_port = udp_data.src_port;
} else {
to_addr.sin6_port = local_port;
}
} else { } else {
to_addr.sin6_port = remote_port; to_addr.sin6_port = remote_port;
} }
log_info("send_dhcpv4_response(): sending %s on %s to %s port %d", log_info("send_dhcpv4_response(): sending %s on %s to %s port %d",
dhcpv6_type_names[raw->data[32]], dhcpv6_type_names[raw->data[36]],
name, name,
inet_ntop(AF_INET6, raw->data + 16, pbuf, sizeof(pbuf)), inet_ntop(AF_INET6, raw->data + 16, pbuf, sizeof(pbuf)),
ntohs(to_addr.sin6_port)); ntohs(to_addr.sin6_port));
send_ret = send_packet6(ip, raw->data + 32, raw->len - 32, &to_addr); send_ret = send_packet6(ip, raw->data + 36, raw->len - 36, &to_addr);
if (send_ret < 0) { if (send_ret < 0) {
log_error("send_dhcpv4_response: send_packet6(): %m"); log_error("send_dhcpv4_response: send_packet6(): %m");
} else if (send_ret != raw->len - 32) { } else if (send_ret != raw->len - 36) {
log_error("send_dhcpv4_response: send_packet6() " log_error("send_dhcpv4_response: send_packet6() "
"sent %d of %d bytes", "sent %d of %d bytes",
send_ret, raw->len - 32); send_ret, raw->len - 36);
} }
} }
#endif /* DHCP4o6 */ #endif /* DHCP4o6 */
@ -857,6 +872,9 @@ static const int required_opts_solicit[] = {
}; };
static const int required_opts_agent[] = { static const int required_opts_agent[] = {
D6O_INTERFACE_ID, D6O_INTERFACE_ID,
#if defined(RELAY_PORT)
D6O_RELAY_SOURCE_PORT,
#endif
D6O_RELAY_MSG, D6O_RELAY_MSG,
0 0
}; };
@ -6854,6 +6872,35 @@ dhcpv6_relay_forw(struct data_string *reply_ret, struct packet *packet) {
data_string_forget(&a_opt, MDL); data_string_forget(&a_opt, MDL);
} }
#if defined(RELAY_PORT)
/*
* Append the relay_source_port option if present.
*/
oc = lookup_option(&dhcpv6_universe, packet->options,
D6O_RELAY_SOURCE_PORT);
if (oc != NULL) {
if (!evaluate_option_cache(&a_opt, packet,
NULL, NULL,
packet->options, NULL,
&global_scope, oc, MDL)) {
log_error("dhcpv6_relay_forw: error evaluating "
"Relay Source Port.");
goto exit;
}
if (!save_option_buffer(&dhcpv6_universe, opt_state, NULL,
(unsigned char *)a_opt.data,
a_opt.len,
D6O_RELAY_SOURCE_PORT, 0)) {
log_error("dhcpv6_relay_forw: error saving "
"Relay Source Port.");
goto exit;
}
data_string_forget(&a_opt, MDL);
packet->relay_source_port = ISC_TRUE;
}
#endif
/* /*
* Append our encapsulated stuff for caller. * Append our encapsulated stuff for caller.
*/ */
@ -7147,6 +7194,35 @@ dhcp4o6_relay_forw(struct data_string *reply_ret, struct packet *packet) {
data_string_forget(&a_opt, MDL); data_string_forget(&a_opt, MDL);
} }
#if defined(RELAY_PORT)
/*
* Append the relay_source_port option if present.
*/
oc = lookup_option(&dhcpv6_universe, packet->options,
D6O_RELAY_SOURCE_PORT);
if (oc != NULL) {
if (!evaluate_option_cache(&a_opt, packet,
NULL, NULL,
packet->options, NULL,
&global_scope, oc, MDL)) {
log_error("dhcpv4o6_relay_forw: error evaluating "
"Relay Source Port.");
goto exit;
}
if (!save_option_buffer(&dhcpv6_universe, opt_state, NULL,
(unsigned char *)a_opt.data,
a_opt.len,
D6O_RELAY_SOURCE_PORT, 0)) {
log_error("dhcpv4o6_relay_forw: error saving "
"Relay Source Port.");
goto exit;
}
data_string_forget(&a_opt, MDL);
packet->relay_source_port = ISC_TRUE;
}
#endif
/* /*
* Append our encapsulated stuff for caller. * Append our encapsulated stuff for caller.
*/ */
@ -7436,12 +7512,13 @@ exit:
* \brief Forward a DHCPv4-query message to the DHCPv4 side * \brief Forward a DHCPv4-query message to the DHCPv4 side
* (DHCPv6 server function) * (DHCPv6 server function)
* *
* Format: interface:16 + address:16 + DHCPv6 DHCPv4-query message * Format: interface:16 + address:16 + udp:4 + DHCPv6 DHCPv4-query message
* *
* \brief packet the DHCPv6 DHCPv4-query message * \brief packet the DHCPv6 DHCPv4-query message
*/ */
static void forw_dhcpv4_query(struct packet *packet) { static void forw_dhcpv4_query(struct packet *packet) {
struct data_string ds; struct data_string ds;
struct udp_data4o6 udp_data;
unsigned len; unsigned len;
int cc; int cc;
@ -7458,7 +7535,7 @@ static void forw_dhcpv4_query(struct packet *packet) {
} }
/* Get a buffer. */ /* Get a buffer. */
len = packet->packet_length + 32; len = packet->packet_length + 36;
memset(&ds, 0, sizeof(ds)); memset(&ds, 0, sizeof(ds));
if (!buffer_allocate(&ds.buffer, len, MDL)) { if (!buffer_allocate(&ds.buffer, len, MDL)) {
log_error("forw_dhcpv4_query: " log_error("forw_dhcpv4_query: "
@ -7472,7 +7549,10 @@ static void forw_dhcpv4_query(struct packet *packet) {
strncpy((char *)ds.buffer->data, packet->interface->name, 16); strncpy((char *)ds.buffer->data, packet->interface->name, 16);
memcpy(ds.buffer->data + 16, memcpy(ds.buffer->data + 16,
packet->client_addr.iabuf, 16); packet->client_addr.iabuf, 16);
memcpy(ds.buffer->data + 32, memset(&udp_data, 0, sizeof(udp_data));
udp_data.src_port = packet->client_port;
memcpy(ds.buffer->data + 32, &udp_data, 4);
memcpy(ds.buffer->data + 36,
(unsigned char *)packet->raw, (unsigned char *)packet->raw,
packet->packet_length); packet->packet_length);
@ -7690,6 +7770,15 @@ dhcpv6(struct packet *packet) {
to_addr.sin6_port = packet->client_port; to_addr.sin6_port = packet->client_port;
#endif #endif
#if defined(RELAY_PORT)
/*
* Check relay source port.
*/
if (packet->relay_source_port) {
to_addr.sin6_port = packet->client_port;
}
#endif
memcpy(&to_addr.sin6_addr, packet->client_addr.iabuf, memcpy(&to_addr.sin6_addr, packet->client_addr.iabuf,
sizeof(to_addr.sin6_addr)); sizeof(to_addr.sin6_addr));
@ -7716,7 +7805,7 @@ dhcpv6(struct packet *packet) {
* Receive a message with a DHCPv4-query inside from the DHCPv6 server. * Receive a message with a DHCPv4-query inside from the DHCPv6 server.
* (code copied from \ref do_packet6() \ref and dhcpv6()) * (code copied from \ref do_packet6() \ref and dhcpv6())
* *
* Format: interface:16 + address:16 + DHCPv6 DHCPv4-query message * Format: interface:16 + address:16 + udp:4 + DHCPv6 DHCPv4-query message
* *
* \param raw the DHCPv6 DHCPv4-query message raw content * \param raw the DHCPv6 DHCPv4-query message raw content
*/ */
@ -7730,6 +7819,7 @@ static void recv_dhcpv4_query(struct data_string *raw) {
const struct dhcpv4_over_dhcpv6_packet *msg; const struct dhcpv4_over_dhcpv6_packet *msg;
struct data_string reply; struct data_string reply;
struct data_string ds; struct data_string ds;
struct udp_data4o6 udp_data;
unsigned len; unsigned len;
int cc; int cc;
@ -7748,14 +7838,17 @@ static void recv_dhcpv4_query(struct data_string *raw) {
iaddr.len = 16; iaddr.len = 16;
memcpy(iaddr.iabuf, raw->data + 16, 16); memcpy(iaddr.iabuf, raw->data + 16, 16);
memset(&udp_data, 0, sizeof(udp_data));
memcpy(&udp_data, raw->data + 32, 4);
/* /*
* From do_packet6(). * From do_packet6().
*/ */
if (!packet6_len_okay((char *)raw->data + 32, raw->len - 32)) { if (!packet6_len_okay((char *)raw->data + 36, raw->len - 36)) {
log_error("recv_dhcpv4_query: " log_error("recv_dhcpv4_query: "
"short packet from %s, len %d, dropped", "short packet from %s, len %d, dropped",
piaddr(iaddr), raw->len - 32); piaddr(iaddr), raw->len - 36);
return; return;
} }
@ -7774,18 +7867,18 @@ static void recv_dhcpv4_query(struct data_string *raw) {
return; return;
} }
packet->raw = (struct dhcp_packet *)(raw->data + 32); packet->raw = (struct dhcp_packet *)(raw->data + 36);
packet->packet_length = raw->len - 32; packet->packet_length = raw->len - 36;
packet->client_port = remote_port; packet->client_port = udp_data.src_port;
packet->client_addr = iaddr; packet->client_addr = iaddr;
interface_reference(&packet->interface, ip, MDL); interface_reference(&packet->interface, ip, MDL);
msg_type = raw->data[32]; msg_type = raw->data[36];
if ((msg_type == DHCPV6_RELAY_FORW) || if ((msg_type == DHCPV6_RELAY_FORW) ||
(msg_type == DHCPV6_RELAY_REPL)) { (msg_type == DHCPV6_RELAY_REPL)) {
int relaylen = int relaylen =
(int)(offsetof(struct dhcpv6_relay_packet, options)); (int)(offsetof(struct dhcpv6_relay_packet, options));
relay = (const struct dhcpv6_relay_packet *)(raw->data + 32); relay = (const struct dhcpv6_relay_packet *)(raw->data + 36);
packet->dhcpv6_msg_type = relay->msg_type; packet->dhcpv6_msg_type = relay->msg_type;
/* relay-specific data */ /* relay-specific data */
@ -7797,7 +7890,7 @@ static void recv_dhcpv4_query(struct data_string *raw) {
if (!parse_option_buffer(packet->options, if (!parse_option_buffer(packet->options,
relay->options, relay->options,
raw->len - 32 - relaylen, raw->len - 36 - relaylen,
&dhcpv6_universe)) { &dhcpv6_universe)) {
/* no logging here, as parse_option_buffer() logs all /* no logging here, as parse_option_buffer() logs all
cases where it fails */ cases where it fails */
@ -7808,7 +7901,7 @@ static void recv_dhcpv4_query(struct data_string *raw) {
(msg_type == DHCPV6_DHCPV4_RESPONSE)) { (msg_type == DHCPV6_DHCPV4_RESPONSE)) {
int msglen = int msglen =
(int)(offsetof(struct dhcpv4_over_dhcpv6_packet, options)); (int)(offsetof(struct dhcpv4_over_dhcpv6_packet, options));
msg = (struct dhcpv4_over_dhcpv6_packet *)(raw->data + 32); msg = (struct dhcpv4_over_dhcpv6_packet *)(raw->data + 36);
packet->dhcpv6_msg_type = msg->msg_type; packet->dhcpv6_msg_type = msg->msg_type;
/* message-specific data */ /* message-specific data */
@ -7817,7 +7910,7 @@ static void recv_dhcpv4_query(struct data_string *raw) {
if (!parse_option_buffer(packet->options, if (!parse_option_buffer(packet->options,
msg->options, msg->options,
raw->len - 32 - msglen, raw->len - 36 - msglen,
&dhcpv6_universe)) { &dhcpv6_universe)) {
/* no logging here, as parse_option_buffer() logs all /* no logging here, as parse_option_buffer() logs all
cases where it fails */ cases where it fails */
@ -7878,18 +7971,19 @@ static void recv_dhcpv4_query(struct data_string *raw) {
*/ */
build_dhcpv6_reply(&reply, packet); build_dhcpv6_reply(&reply, packet);
packet_dereference(&packet, MDL); if (reply.data == NULL) {
packet_dereference(&packet, MDL);
if (reply.data == NULL)
return; return;
}
/* /*
* Forward the response. * Forward the response.
*/ */
len = reply.len + 32; len = reply.len + 36;
memset(&ds, 0, sizeof(ds)); memset(&ds, 0, sizeof(ds));
if (!buffer_allocate(&ds.buffer, len, MDL)) { if (!buffer_allocate(&ds.buffer, len, MDL)) {
log_error("recv_dhcpv4_query: no memory."); log_error("recv_dhcpv4_query: no memory.");
packet_dereference(&packet, MDL);
return; return;
} }
ds.data = ds.buffer->data; ds.data = ds.buffer->data;
@ -7897,7 +7991,15 @@ static void recv_dhcpv4_query(struct data_string *raw) {
memcpy(ds.buffer->data, name, 16); memcpy(ds.buffer->data, name, 16);
memcpy(ds.buffer->data + 16, iaddr.iabuf, 16); memcpy(ds.buffer->data + 16, iaddr.iabuf, 16);
memcpy(ds.buffer->data + 32, reply.data, reply.len); udp_data.rsp_opt_exist = packet->relay_source_port ? 1 : 0;
memcpy(ds.buffer->data + 32, &udp_data, 4);
memcpy(ds.buffer->data + 36, reply.data, reply.len);
/*
* Now we can release the packet.
*/
packet_dereference(&packet, MDL);
cc = send(dhcp4o6_fd, ds.data, ds.len, 0); cc = send(dhcp4o6_fd, ds.data, ds.len, 0);
if (cc < 0) if (cc < 0)
log_error("recv_dhcpv4_query: send(): %m"); log_error("recv_dhcpv4_query: send(): %m");

View File

@ -169,6 +169,7 @@ static struct option agent_options[] = {
{ "agent-id", "I", &agent_universe, 3, 1 }, { "agent-id", "I", &agent_universe, 3, 1 },
{ "DOCSIS-device-class", "L", &agent_universe, 4, 1 }, { "DOCSIS-device-class", "L", &agent_universe, 4, 1 },
{ "link-selection", "I", &agent_universe, 5, 1 }, { "link-selection", "I", &agent_universe, 5, 1 },
{ "relay-port", "Z", &agent_universe, 19, 1 },
{ NULL, NULL, NULL, 0, 0 } { NULL, NULL, NULL, 0, 0 }
}; };