41#include <systemd/sd-daemon.h>
90int dfd[2] = { -1, -1 };
145 unsigned int,
unsigned int,
struct iaddr,
160static void request_v4_interface(
const char* name,
int flags);
162static const char copyright[] =
163"Copyright 2004-2022 Internet Systems Consortium.";
164static const char arr[] =
"All rights reserved.";
165static const char message[] =
166"Internet Systems Consortium DHCP Relay Agent";
167static const char url[] =
168"For info, please visit https://www.isc.org/software/dhcp/";
174#define DHCRELAY_USAGE \
175"Usage: %s [-4] [-d] [-q] [-a] [-D]\n" \
176" [-A <length>] [-c <hops>]\n" \
177" [-p <port> | -rp <relay-port>]\n" \
178" [-pf <pid-file>] [--no-pid]\n"\
179" [-m append|replace|forward|discard]\n" \
180" [-i interface0 [ ... -i interfaceN]\n" \
181" [-iu interface0 [ ... -iu interfaceN]\n" \
182" [-id interface0 [ ... -id interfaceN]\n" \
183" [-U interface] [-g <ip-address>]\n" \
184" server0 [ ... serverN]\n\n" \
185" %s -6 [-d] [-q] [-I] [-c <hops>]\n" \
186" [-p <port> | -rp <relay-port>]\n" \
187" [-pf <pid-file>] [--no-pid]\n" \
188" [-s <subscriber-id>]\n" \
189" -l lower0 [ ... -l lowerN]\n" \
190" -u upper0 [ ... -u upperN]\n" \
191" lower (client link): [address%%]interface[#index]\n" \
192" upper (server link): [address%%]interface\n\n" \
193" %s {--version|--help|-h}"
195#define DHCRELAY_USAGE \
196"Usage: %s [-4] [-d] [-q] [-a] [-D]\n" \
197" [-A <length>] [-c <hops>] [-p <port>]\n" \
198" [-pf <pid-file>] [--no-pid]\n"\
199" [-m append|replace|forward|discard]\n" \
200" [-i interface0 [ ... -i interfaceN]\n" \
201" [-iu interface0 [ ... -iu interfaceN]\n" \
202" [-id interface0 [ ... -id interfaceN]\n" \
203" [-U interface] [-g <ip-address>]\n" \
204" server0 [ ... serverN]\n\n" \
205" %s -6 [-d] [-q] [-I] [-c <hops>] [-p <port>]\n" \
206" [-pf <pid-file>] [--no-pid]\n" \
207" [-s <subscriber-id>]\n" \
208" -l lower0 [ ... -l lowerN]\n" \
209" -u upper0 [ ... -u upperN]\n" \
210" lower (client link): [address%%]interface[#index]\n" \
211" upper (server link): [address%%]interface\n\n" \
212" %s {--version|--help|-h}"
216#define DHCRELAY_USAGE \
217"Usage: %s [-d] [-q] [-a] [-D] [-A <length>] [-c <hops>]\n" \
218" [-p <port> | -rp <relay-port>]\n" \
219" [-pf <pid-file>] [--no-pid]\n" \
220" [-m append|replace|forward|discard]\n" \
221" [-i interface0 [ ... -i interfaceN]\n" \
222" [-iu interface0 [ ... -iu interfaceN]\n" \
223" [-id interface0 [ ... -id interfaceN]\n" \
224" [-U interface] [-g <ip-address>]\n" \
225" server0 [ ... serverN]\n\n" \
226" %s {--version|--help|-h}"
228#define DHCRELAY_USAGE \
229"Usage: %s [-d] [-q] [-a] [-D] [-A <length>] [-c <hops>] [-p <port>]\n" \
230" [-pf <pid-file>] [--no-pid]\n" \
231" [-m append|replace|forward|discard]\n" \
232" [-i interface0 [ ... -i interfaceN]\n" \
233" [-iu interface0 [ ... -iu interfaceN]\n" \
234" [-id interface0 [ ... -id interfaceN]\n" \
235" [-U interface] [-g <ip-address>]\n" \
236" server0 [ ... serverN]\n\n" \
237" %s {--version|--help|-h}"
256static const char use_noarg[] =
"No argument for command: %s";
259#if !defined (USE_BPF_RECEIVE) && !defined (USE_LPF_RECEIVE)
264static const char use_badproto[] =
"Protocol already set, %s inappropriate";
265static const char use_v4command[] =
"Command not used for DHCPv6: %s";
266static const char use_v6command[] =
"Command not used for DHCPv4: %s";
270usage(
const char *
sfmt,
const char *
sarg) {
277#ifdef PRINT_SPECIFIC_CL_ERRORS
334 for (
i = 1;
i < argc;
i++) {
381 log_fatal(
"Can't initialize context: %s",
393 for (
i = 1;
i < argc;
i++) {
415 usage(use_noarg,
argv[
i-1]);
422 log_debug(
"binding to user-specified port %d",
427 usage(use_noarg,
argv[
i-1]);
432 log_debug(
"binding to user-specified relay port %d",
439 usage(use_noarg,
argv[
i-1]);
444 usage(
"Bad hop count to -c: %s",
argv[
i]);
454 usage(use_noarg,
argv[
i-1]);
467 usage(use_noarg,
argv[
i-1]);
480 usage(use_noarg,
argv[
i-1]);
502 usage(use_noarg,
argv[
i-1]);
508 "longest possible MTU\n",
519 usage(use_noarg,
argv[
i-1]);
529 usage(
"Unknown argument to -m: %s",
argv[
i]);
532 usage(use_noarg,
argv[
i-1]);
535 usage(
"more than one uplink (-U) specified: %s"
542 log_fatal(
"%s: uplink interface_allocate: %s",
548 " it cannot exceed: %ld characters",
563 usage(use_noarg,
argv[
i-1]);
572 usage(
"Invalid gateway address '%s'",
argv[
i]);
602 usage(use_noarg,
argv[
i-1]);
613 usage(use_noarg,
argv[
i-1]);
624 usage(use_noarg,
argv[
i-1]);
633 usage(use_noarg,
argv[
i-1]);
638 }
else if (
argv[
i][0] ==
'-') {
639 usage(
"Unknown command: %s",
argv[
i]);
675#if defined(RELAY_PORT) && \
676 !defined (USE_BPF_RECEIVE) && !defined (USE_LPF_RECEIVE)
707 log_info (
"Dropped all unnecessary capabilities.");
763 sp->to.sin_len =
sizeof sp->to;
773 log_info(
"Must specify at least one lower "
774 "and one upper interface.\n");
786 log_fatal(
"Unable to find the RELAY_MSG "
787 "option definition.");
792 log_fatal(
"Unable to find the INTERFACE_ID "
793 "option definition.");
817 if (
dfd[0] != -1 &&
dfd[1] != -1) {
860#if defined(ENABLE_GENTLE_SHUTDOWN)
872 log_info (
"Dropped all capabilities.");
876#ifdef HAVE_LIBSYSTEMD
879 "STATUS=Dispatching packets...\n"
881 (
unsigned long)
getpid());
893 unsigned int length,
unsigned int from_port,
struct iaddr from,
901 log_info(
"Discarding packet with invalid hlen, received on "
902 "%s interface.",
ip->name);
905 if (
ip->address_count < 1 ||
ip->addresses ==
NULL) {
906 log_info(
"Discarding packet received on %s interface that "
907 "has no IPv4 address assigned.",
ip->name);
913 if (
packet->giaddr.s_addr) {
917 for (
i = 0 ;
i <
out->address_count ;
i++ ) {
918 if (
out->addresses[
i].s_addr ==
935 log_debug(
"Dropping reply received on %s",
ip->name);
942 to.sin_addr =
packet->yiaddr;
956 to.sin_len =
sizeof to;
960 hto.hbuf[0] =
packet->htype;
961 hto.hlen =
packet->hlen + 1;
972 log_error(
"Packet to bogus giaddr %s.\n",
986 log_debug(
"Forwarded BOOTREPLY for %s to %s",
1002 log_debug(
"Dropping request received on %s",
ip->name);
1018 if (!
packet->giaddr.s_addr)
1034 log_debug(
"Forwarded BOOTREQUEST for %s to %s",
1130 size_t mlen = op[1] + 2;
1193 unsigned circuit_id_len = 0;
1200 i + buf[
i + 1] + 2 > len) {
1213 i += buf[
i + 1] + 2;
1229 if (
ip->circuit_id &&
1273 && (
packet->giaddr.s_addr == 0));
1364 size_t mlen = op[1] + 2;
1397 if ((
ip->circuit_id_len > 255) ||(
ip->circuit_id_len < 1))
1398 log_fatal(
"Circuit ID length %d out of range [1-255] on "
1399 "%s\n",
ip->circuit_id_len,
ip->name);
1402 if (
ip->remote_id) {
1403 if (
ip->remote_id_len > 255 ||
ip->remote_id_len < 1)
1404 log_fatal(
"Remote ID length %d out of range [1-255] "
1405 "on %s\n",
ip->remote_id_len,
ip->name);
1423 log_fatal(
"Total agent option length(%u) out of range "
1424 "[3 - 255] on %s\n",
optlen,
ip->name);
1439 *
sp++ =
ip->circuit_id_len;
1441 sp +=
ip->circuit_id_len;
1444 if (
ip->remote_id) {
1446 *
sp++ =
ip->remote_id_len;
1448 sp +=
ip->remote_id_len;
1460 log_debug (
"Adding link selection suboption"
1473 log_error(
"No room in packet (used %d of %d) "
1474 "for %d-byte relay agent option: omitted",
1513 log_fatal(
"No support for multiple interfaces.");
1529 usage(
"Interface name '%s' too long",
ifname);
1535 log_fatal(
"Down interface '%s' declared twice.",
1542 log_info(
"parse_downstream: Interface '%s' is "
1543 "both down and up.",
ifname);
1576 log_fatal(
"Bad link address '%s'", addr);
1613 log_info(
"parse_upstream: Interface '%s' is "
1614 "both down and up.",
ifname);
1659 if (
dp->ifp->v6address_count == 0)
1660 log_fatal(
"Interface '%s' has no IPv6 addresses.",
1668 for (
i = 0;
i <
dp->ifp->v6address_count;
i++) {
1674 &
dp->link.sin6_addr,
1675 sizeof(
dp->link.sin6_addr)))
1678 if (
i ==
dp->ifp->v6address_count)
1679 log_fatal(
"Interface %s does not have global IPv6 "
1680 "address assigned.",
dp->ifp->name);
1683 &
dp->ifp->v6addresses[
i],
1684 sizeof(
dp->link.sin6_addr));
1688 dp->id =
dp->ifp->index;
1695 up->link.sin6_len =
sizeof(
up->link);
1698 if (
up->ifp->v6address_count == 0)
1699 log_fatal(
"Interface '%s' has no IPv6 addresses.",
1717#if defined(RELAY_PORT)
1749 log_info(
"Relaying %s from %s port %d going up.",
1761 log_info(
"Discarding %s from %s port %d going up.",
1768 log_info(
"Unknown %d type from %s port %d going up.",
1790 log_info(
"Shan't get back the interface.");
1810 log_fatal(
"No memory for upwards options.");
1822 log_info(
"Don't know the interface.");
1851#if defined(RELAY_PORT)
1865 log_error(
"Can't save relay-source-port.");
1909#if defined(RELAY_PORT)
1918 log_info(
"Discarding %s from %s port %d going down.",
1923 log_info(
"Unknown %d type from %s port %d going down.",
1933#if defined(RELAY_PORT)
1936 memset(&to, 0,
sizeof(to));
1939 to.sin6_len =
sizeof(to);
1968 (
if_id.len !=
sizeof(
int))) {
1969 log_info(
"Can't evaluate interface-id.");
1995 log_info(
"Can't find the down interface.");
2002 switch (
msg->msg_type) {
2007#if defined(RELAY_PORT)
2019 "relay-source-port.");
2045 log_info(
"Relaying %s to %s port %d down.",
2048 ntohs(to.sin6_port));
2061 log_info(
"Discarding %s to %s port %d down.",
2064 ntohs(to.sin6_port));
2068 log_info(
"Unknown %d type to %s port %d down.",
2071 ntohs(to.sin6_port));
2113 log_info(
"Can't process packet from interface '%s'.",
2130#if defined(DHCPv6) && defined(DHCP4o6)
2192void request_v4_interface(
const char* name,
int flags) {
2197 if (len >=
sizeof(
tmp->name)) {
2198 log_fatal(
"%s: interface name too long (is %d)",
name, len);
2207 log_debug(
"Requesting: %s as upstream: %c downstream: %c",
name,
void data_string_forget(struct data_string *data, const char *file, int line)
int option_state_allocate(struct option_state **ptr, const char *file, int line)
int option_state_dereference(struct option_state **ptr, const char *file, int line)
int save_option_buffer(struct universe *universe, struct option_state *options, struct buffer *bp, unsigned char *buffer, unsigned length, unsigned code, int terminatep)
struct option_cache * lookup_option(struct universe *universe, struct option_state *options, unsigned code)
int store_options6(char *buf, int buflen, struct option_state *opt_state, struct packet *packet, const int *required_opts, struct data_string *oro)
char * print_hw_addr(int htype, const int hlen, const unsigned char *data) const
#define _PATH_DHCRELAY_PID
#define DHCPV6_RELAY_REPL
#define D6O_RELAY_SOURCE_PORT
#define DHCPV6_RELAY_FORW
#define DHCPV6_LEASEQUERY
#define DHCPV6_DHCPV4_QUERY
#define DHCPV6_INFORMATION_REQUEST
#define DHCPV6_RECONFIGURE
#define D6O_SUBSCRIBER_ID
#define DHCPV6_DHCPV4_RESPONSE
#define DHCPV6_LEASEQUERY_REPLY
#define DHO_DHCP_MAX_MESSAGE_SIZE
#define DHO_DHCP_AGENT_OPTIONS
#define DHO_DHCP_MESSAGE_TYPE
#define DHCP_OPTIONS_COOKIE
void do_packet6(struct interface_info *, const char *, int, int, const struct iaddr *, isc_boolean_t)
#define INTERFACE_UPSTREAM
#define INTERFACE_REQUESTED
#define INTERFACE_DOWNSTREAM
int supports_multiple_interfaces(struct interface_info *)
#define INTERFACE_STREAMS
ssize_t send_packet(struct interface_info *, struct packet *, struct dhcp_packet *, size_t, struct in_addr, struct sockaddr_in *, struct hardware *)
void(* dhcpv6_packet_handler)(struct interface_info *, const char *, int, int, const struct iaddr *, isc_boolean_t)
#define _PATH_DHCRELAY6_PID
ssize_t send_packet6(struct interface_info *, const unsigned char *, size_t, struct sockaddr_in6 *)
void set_multicast_hop_limit(struct interface_info *info, int hop_limit)
int can_unicast_without_arp(struct interface_info *)
void dhcpv6(struct packet *)
struct tree_cache * global_options[256]
int corrupt_agent_options
void bootp(struct packet *packet)
isc_boolean_t no_pid_file
int find_interface_by_agent_option(struct dhcp_packet *, struct interface_info **, u_int8_t *, int)
void dhcp(struct packet *packet)
isc_result_t find_class(struct class **class, const char *c1, const char *c2, int i)
int main(int argc, char **argv)
struct interface_info * uplink
int add_rfc3527_suboption
int drop_agent_mismatches
int dhcp_max_agent_option_packet_length
int check_collection(struct packet *p, struct lease *l, struct collection *c)
isc_boolean_t use_fake_gw
isc_boolean_t no_dhcrelay_pid
int strip_relay_agent_options(struct interface_info *, struct interface_info **, struct dhcp_packet *, unsigned)
int server_packets_relayed
void classify(struct packet *p, struct class *c)
int add_relay_agent_options(struct interface_info *, struct dhcp_packet *, unsigned, struct in_addr)
isc_result_t dhcp_set_control_state(control_object_state_t oldstate, control_object_state_t newstate)
int client_packets_relayed
enum @28 agent_relay_mode
struct server_list * servers
const char * path_dhcrelay_pid
int parse_allow_deny(struct option_cache **oc, struct parse *p, int i)
struct option * requested_opts[2]
struct interface_info * interfaces
struct interface_info * fallback_interface
void discover_interfaces(int state)
int quiet_interface_discovery
isc_result_t interface_setup()
void(* bootp_packet_handler)(struct interface_info *, struct dhcp_packet *, unsigned, unsigned int, struct iaddr, struct hardware *)
void interface_snorf(struct interface_info *tmp, int ir)
u_int16_t validate_port(char *port)
const char * piaddr(const struct iaddr addr)
isc_result_t dhcp_context_create(int flags, struct in_addr *local4, struct in6_addr *local6)
void dhcp_signal_handler(int signal)
#define DHCP_CONTEXT_PRE_DB
#define ISC_R_NOTIMPLEMENTED
isc_result_t omapi_init(void)
void * dmalloc(size_t, const char *, int)
int log_error(const char *,...) __attribute__((__format__(__printf__
int int int log_debug(const char *,...) __attribute__((__format__(__printf__
void log_fatal(const char *,...) __attribute__((__format__(__printf__
int int log_info(const char *,...) __attribute__((__format__(__printf__
unsigned char options[FLEXIBLE_ARRAY_MEMBER]
unsigned char link_address[16]
unsigned char peer_address[16]
struct interface_info * next
struct in_addr * addresses
struct in6_addr dhcpv6_link_address
unsigned char dhcpv6_msg_type
unsigned char dhcpv6_hop_count
struct interface_info * interface
struct in6_addr dhcpv6_peer_address
struct option_state * options
struct server_list * next
option_code_hash_t * code_hash
const int dhcpv6_type_name_max
const char * dhcpv6_type_names[]
struct universe dhcpv6_universe
void initialize_common_option_spaces()
int evaluate_option_cache(struct data_string *result, struct packet *packet, struct lease *lease, struct client_state *client_state, struct option_state *in_options, struct option_state *cfg_options, struct binding_scope **scope, struct option_cache *oc, const char *file, int line)
struct binding_scope * global_scope