Update isc-dhcp source to v4.3.3-6; create new patch against it (#1164)

- Found a bug in v4.3.1-6 in which dhcrelay would not start if
   passed an interface name with a length of 15 characters due
   to truncated copy of interface name in common/lpf.c.
   Bug was fixed in v4.3.2.

 - v4.3.3-6 is the newest version we can build for Debian Jessie, as all
   newer versions require newer versions of debhelper and
   libbind-export-dev dependencies than are available for Jessie.
This commit is contained in:
Joe LeVeque 2017-11-17 14:51:48 -08:00 committed by GitHub
parent 2a69f372c3
commit 223a38c02f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 445 additions and 445 deletions

View File

@ -1,6 +1,6 @@
# isc-dhcp packages
ISC_DHCP_VERSION = 4.3.1-6
ISC_DHCP_VERSION = 4.3.3-6
export ISC_DHCP_VERSION

View File

@ -12,11 +12,11 @@ $(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% :
# Clone isc-dhcp repo
git clone https://anonscm.debian.org/cgit/pkg-dhcp/isc-dhcp.git
pushd ./isc-dhcp
git checkout -f debian/4.3.1-6
git checkout -f debian/$(ISC_DHCP_VERSION)
popd
# Apply patch
patch -p1 < isc-dhcp-4.3.1_dhcrelay-custom-circuit_id-remote_id-and-bridge-iface-support.patch
patch -p1 < isc-dhcp-$(ISC_DHCP_VERSION)_dhcrelay-custom-circuit_id-remote_id-and-bridge-iface-support.patch
# Build source and Debian packages
pushd ./isc-dhcp

View File

@ -1,442 +0,0 @@
This patch adds the following functionality to dhcrelay in isc-dhcp v4.3.1-6:
* Add customizable Circuit ID and Remote ID fields
* Support for obtaining name of physical interfaces that are part of a bridge interface
diff -ruN a/isc-dhcp/relay/dhcrelay.c b/isc-dhcp/relay/dhcrelay.c
--- a/isc-dhcp/relay/dhcrelay.c 2017-10-03 01:46:19.811524700 +0000
+++ b/isc-dhcp/relay/dhcrelay.c 2017-10-03 01:45:50.699524700 +0000
@@ -73,6 +73,8 @@
did not match any known circuit ID. */
int missing_circuit_id = 0; /* Circuit ID option in matching RAI option
was missing. */
+const char *agent_circuit_id_fmt = NULL; /* Circuit ID custom format string. */
+const char *agent_remote_id_fmt = NULL; /* Remote ID custom format string. */
int max_hop_count = 10; /* Maximum hop count */
#ifdef DHCPv6
@@ -120,6 +122,14 @@
char *dhcrelay_sub_id = NULL;
#endif
+struct interface_name_alias_tuple {
+ char if_name[IFNAMSIZ + 1];
+ char if_alias[IFNAMSIZ + 1];
+};
+
+static struct interface_name_alias_tuple *g_interface_name_alias_map = NULL;
+static size_t g_interface_name_alias_map_size = 0;
+
static void do_relay4(struct interface_info *, struct dhcp_packet *,
unsigned int, unsigned int, struct iaddr,
struct hardware *);
@@ -132,6 +142,10 @@
struct interface_info **,
struct dhcp_packet *, unsigned);
+static int load_interface_alias_map(const char *port_alias_map_file_path);
+static int get_interface_alias_by_name(const char *if_name, char *if_alias_out);
+static void free_interface_alias_map(void);
+
static const char copyright[] =
"Copyright 2004-2014 Internet Systems Consortium.";
static const char arr[] = "All rights reserved.";
@@ -140,28 +154,42 @@
static const char url[] =
"For info, please visit https://www.isc.org/software/dhcp/";
+#define DHCRELAY_OPTION82_USAGE \
+"circuit_id/remote_id interpreted sequences are:\n" \
+"\n" \
+" %%%% A single %%\n" \
+" %%h Hostname of device\n" \
+" %%p Alias of interface that generated the request\n" \
+" %%P Hardware address of interface that generated the request\n" \
+" %%C Client hardware address\n" \
+" %%I DHCP relay agent IP Address\n" \
+
#ifdef DHCPv6
#define DHCRELAY_USAGE \
-"Usage: dhcrelay [-4] [-d] [-q] [-a] [-D]\n"\
+"Usage: dhcrelay [-4] [-d] [-q] [-a <circuit_id> <remote_id>] [-D]\n"\
" [-A <length>] [-c <hops>] [-p <port>]\n" \
" [-pf <pid-file>] [--no-pid]\n"\
" [-m append|replace|forward|discard]\n" \
+" [--name-alias-map-file <name-alias-map-file>]\n" \
" [-i interface0 [ ... -i interfaceN]\n" \
" server0 [ ... serverN]\n\n" \
" dhcrelay -6 [-d] [-q] [-I] [-c <hops>] [-p <port>]\n" \
" [-pf <pid-file>] [--no-pid]\n" \
+" [--name-alias-map-file <name-alias-map-file>]\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"
+" upper (server link): [address%%]interface\n\n" DHCRELAY_OPTION82_USAGE
#else
#define DHCRELAY_USAGE \
-"Usage: dhcrelay [-d] [-q] [-a] [-D] [-A <length>] [-c <hops>] [-p <port>]\n" \
-" [-pf <pid-file>] [--no-pid]\n" \
+"Usage: dhcrelay [-d] [-q] [-a <circuit_id> <remote_id>] [-D]\n" \
+" [-A <length>] [-c <hops>] [-p <port>]\n" \
+" [-pf <pid-file>] [--no-pid]\n"\
" [-m append|replace|forward|discard]\n" \
+" [--name-alias-map-file <name-alias-map-file>]\n" \
" [-i interface0 [ ... -i interfaceN]\n" \
-" server0 [ ... serverN]\n\n"
+" server0 [ ... serverN]\n\n" DHCRELAY_OPTION82_USAGE
#endif
static void usage() {
@@ -287,6 +315,15 @@
local_family_set = 1;
local_family = AF_INET;
#endif
+ if (++i == argc)
+ usage();
+
+ if (argv[i] != NULL && argv[i][0] != '-')
+ agent_circuit_id_fmt = argv[i++];
+
+ if (argv[i] != NULL && argv[i][0] != '-')
+ agent_remote_id_fmt = argv[i];
+
add_agent_options = 1;
} else if (!strcmp(argv[i], "-A")) {
#ifdef DHCPv6
@@ -383,6 +420,13 @@
no_dhcrelay_pid = ISC_TRUE;
} else if (!strcmp(argv[i], "--no-pid")) {
no_pid_file = ISC_TRUE;
+ } else if (!strcmp(argv[i], "--name-alias-map-file")) {
+ if (++i == argc)
+ usage();
+ if (load_interface_alias_map(argv[i]) != 0)
+ log_fatal("Failed to load interface name-alias map.");
+ path_dhcrelay_pid = argv[i];
+ no_dhcrelay_pid = ISC_TRUE;
} else if (!strcmp(argv[i], "--version")) {
log_info("isc-dhcrelay-%s", PACKAGE_VERSION);
exit(0);
@@ -602,6 +646,8 @@
dispatch();
/* In fact dispatch() never returns. */
+ free_interface_alias_map();
+
return (0);
}
@@ -690,10 +736,9 @@
&to, htop) < 0) {
++server_packet_errors;
} else {
- log_debug("Forwarded BOOTREPLY for %s to %s",
- print_hw_addr(packet->htype, packet->hlen,
- packet->chaddr),
- inet_ntoa(to.sin_addr));
+ //log_debug("Forwarded BOOTREPLY for %s to %s",
+ // print_hw_addr(packet->htype, packet->hlen, packet->chaddr),
+ // inet_ntoa(to.sin_addr));
++server_packets_relayed;
}
@@ -732,10 +777,10 @@
&sp->to, NULL) < 0) {
++client_packet_errors;
} else {
- log_debug("Forwarded BOOTREQUEST for %s to %s",
- print_hw_addr(packet->htype, packet->hlen,
- packet->chaddr),
- inet_ntoa(sp->to.sin_addr));
+ //log_debug("Forwarded BOOTREQUEST for %s to %s",
+ // print_hw_addr(packet->htype, packet->hlen, packet->chaddr),
+ // inet_ntoa(sp->to.sin_addr));
+
++client_packets_relayed;
}
}
@@ -937,6 +982,152 @@
return (-1);
}
+static int
+_bridgefdbquery(const char *hwAddr, char *interface, int *vlanid) {
+
+#define xstr(s) str(s)
+#define str(s) #s
+#define FDB_STRING_LEN 100
+#define FDB_BUFFER_LEN (FDB_STRING_LEN + 1)
+
+/*
+ * Format for sscanf() to read the 1st, 3th, and 5th
+ * space-delimited fields
+ *
+ * bridge fdb show output
+ * 6c:64:1a:00:06:13 dev swp35 vlan 0 master bridge permanent
+ */
+#define FDB_LINE_FORMAT "%" xstr(FDB_STRING_LEN) "s %*s " \
+ "%" xstr(FDB_STRING_LEN) "s %*s %d %*s"
+
+ char cmdstr[FDB_BUFFER_LEN];
+ char buf[FDB_BUFFER_LEN];
+ char macAddr[FDB_BUFFER_LEN];
+
+ if ((interface == NULL) || (vlanid == NULL)) {
+ return 0;
+ }
+ sprintf(cmdstr, "bridge fdb show | grep -m 1 %s", hwAddr);
+ FILE *cmd = popen(cmdstr, "r");
+
+ if (cmd != NULL) {
+ while (fgets(buf, sizeof(buf), cmd)) {
+ sscanf(buf, FDB_LINE_FORMAT, macAddr, interface, vlanid);
+ //log_debug("bridgefdbquery: macAddr:%s interface: %s vlanid %d",
+ // macAddr, interface, *vlanid);
+ }
+ pclose(cmd);
+ return 0;
+ }
+
+ return -1;
+}
+
+/*
+ * Format the message that will be used by circuit_id and remote_id
+ */
+static int
+format_relay_agent_rfc3046_msg(struct interface_info *ip, struct dhcp_packet *packet,
+ const char *format, char *msg, size_t msgn) {
+ size_t len = 0;
+ char hostname[HOST_NAME_MAX + 1] = { 0 };
+ char ifname[IFNAMSIZ + 1] = { 0 };
+ char *buf = msg;
+
+ for ( ; format && *format && len < msgn; ++format) {
+ size_t strn = 0;
+ const char *str = NULL;
+
+ if (*format == '%') {
+ switch (*++format) {
+ case '\0':
+ --format;
+ break;
+
+ case '%': /* A literal '%' */
+ str = "%";
+ break;
+
+ case 'h': /* Hostname */
+ gethostname(hostname, HOST_NAME_MAX);
+ str = hostname;
+ break;
+
+ case 'p': /* Name of interface that we received the request from */
+ /*
+ * Query FDB to identify the exact physical interface only when source MAC address
+ * is present and '20: DHCP relay agent IP address' (giaddr) is not present
+ */
+ if (packet->htype && !packet->giaddr.s_addr) {
+ int ret = 0, vlanid = 0;
+
+ ret = _bridgefdbquery(print_hw_addr(packet->htype, packet->hlen, packet->chaddr),
+ ip->name,
+ &vlanid);
+
+ if (ret < 0) {
+ //log_debug("MAC Address: %s (interface:%s vlan:%d) not found in bridge fdb show",
+ // print_hw_addr (packet->htype, packet->hlen, packet->chaddr),
+ // ip->name,
+ // vlanid);
+
+ strncpy(ifname, ip->name, IFNAMSIZ);
+ }
+ else if (strlen(ip->name) > 0) {
+ // Translate SONiC interface name to vendor alias
+ if (get_interface_alias_by_name(ip->name, ifname) < 0) {
+ log_error("Failed to retrieve alias for interface name '%s'. Defaulting to interface name.", ip->name);
+ strncpy(ifname, ip->name, IFNAMSIZ);
+ }
+
+ //log_debug("Mapped interface name '%s' to alias '%s'", ip->name, ifname);
+
+ //log_debug("Adding option 82 interface alias for MAC Address %s as '%s'",
+ // print_hw_addr (packet->htype, packet->hlen, packet->chaddr),
+ // ifname);
+ }
+
+ str = ifname;
+ }
+ break;
+
+ case 'P': /* Physical address of interface that we received the request from */
+ str = print_hw_addr(ip->hw_address.hbuf[0], ip->hw_address.hlen - 1, &ip->hw_address.hbuf[1]);
+ break;
+
+ case 'C': /* 24: Client hardware address */
+ str = print_hw_addr(packet->htype, packet->hlen, packet->chaddr);
+ break;
+
+ case 'I': /* 20: DHCP relay agent IP address */
+ str = inet_ntoa(packet->giaddr);
+ break;
+
+ default:
+ log_error("Option %%%c is unrecognized and will not be formatted!", *format);
+ continue;
+ }
+
+ if (str)
+ strn = strlen(str);
+ } else {
+ str = format;
+ strn += 1;
+ }
+
+ // Do we have room?
+ if ((strn+len) > msgn) {
+ return 0;
+ }
+
+ memcpy(buf+len, str, strn);
+ len += strn;
+ }
+
+ return len;
+}
+
+
/*
* Examine a packet to see if it's a candidate to have a Relay
* Agent Information option tacked onto its tail. If it is, tack
@@ -948,6 +1139,8 @@
int is_dhcp = 0, mms;
unsigned optlen;
u_int8_t *op, *nextop, *sp, *max, *end_pad = NULL;
+ char circuit_id_buf[255] = { '\0', };
+ char remote_id_buf[255] = { '\0', };
/* If we're not adding agent options to packets, we can skip
this. */
@@ -1077,6 +1270,38 @@
op = sp;
#endif
+ /* option82: custom string for circuit_id */
+ if (agent_circuit_id_fmt) {
+ size_t len = 0;
+
+ len = format_relay_agent_rfc3046_msg(ip, packet, agent_circuit_id_fmt,
+ circuit_id_buf, sizeof(circuit_id_buf));
+
+ if (len > 0) {
+ ip->circuit_id = (uint8_t *)circuit_id_buf;
+ ip->circuit_id_len = len;
+
+ //log_debug("Sending on %s option82:circuit_id='%s' (%d)",
+ // ip->name, (char *)ip->circuit_id, ip->circuit_id_len);
+ }
+ }
+
+ /* option82: custom string for remote_id */
+ if (agent_remote_id_fmt) {
+ size_t len = 0;
+
+ len = format_relay_agent_rfc3046_msg(ip, packet, agent_remote_id_fmt,
+ remote_id_buf, sizeof(remote_id_buf));
+
+ if (len > 0) {
+ ip->remote_id = (uint8_t *)remote_id_buf;
+ ip->remote_id_len = len;
+
+ //log_debug("Sending on %s option82:remote_id='%s' (%d)",
+ // ip->name, (char *)ip->remote_id, ip->remote_id_len);
+ }
+ }
+
/* Sanity check. Had better not ever happen. */
if ((ip->circuit_id_len > 255) ||(ip->circuit_id_len < 1))
log_fatal("Circuit ID length %d out of range [1-255] on "
@@ -1102,7 +1327,7 @@
* If not, forward without adding the option.
*/
if (max - sp >= optlen + 3) {
- log_debug("Adding %d-byte relay agent option", optlen + 3);
+ //log_debug("Adding %d-byte relay agent option", optlen + 3);
/* Okay, cons up *our* Relay Agent Information option. */
*sp++ = DHO_DHCP_AGENT_OPTIONS;
@@ -1726,3 +1951,73 @@
exit(0);
}
+
+#define MAX_PORT_CONFIG_LINE_LEN 1024
+
+// Allocates and loads global map g_interface_name_alias_map
+// Also sets global g_interface_name_alias_map_size
+static int
+load_interface_alias_map(const char *port_alias_map_file_path) {
+ int i = 0;
+ FILE *fp = NULL;
+ char line[MAX_PORT_CONFIG_LINE_LEN] = { 0 };
+
+ fp = fopen(port_alias_map_file_path,"r");
+ if (fp == NULL) {
+ log_error("Unable to open %s", port_alias_map_file_path);
+ return -1;
+ }
+
+ g_interface_name_alias_map_size = 0;
+
+ // Count the number of interfaces listed in the file
+ while (fgets(line, sizeof(line), fp)) {
+ g_interface_name_alias_map_size++;
+ }
+
+ // Allocate our map accordingly
+ g_interface_name_alias_map = ((struct interface_name_alias_tuple *)
+ dmalloc((sizeof(struct interface_name_alias_tuple) * g_interface_name_alias_map_size),
+ MDL));
+
+ // Reset file position indicator to beginning of file
+ fseek(fp, 0, SEEK_SET);
+
+ // Every line should contain exactly one name-alias pair
+ while (fgets(line, sizeof(line), fp)) {
+ // Each line should read as "<name><whitespace><alias>"
+ sscanf(line, "%s %s", g_interface_name_alias_map[i].if_name, g_interface_name_alias_map[i].if_alias);
+ i++;
+ }
+
+ fclose(fp);
+
+ log_info("Loaded %d interface name-alias mappings", i);
+
+ return 0;
+}
+
+// Locates alias for port named if_name, copies alias into if_alias_out, up to a
+// max of IFNAMSIZ bytes.
+// Returns 0 on success, -1 on failure
+static int
+get_interface_alias_by_name(const char *if_name, char *if_alias_out) {
+ int i = 0;
+
+ for (i = 0; i < g_interface_name_alias_map_size; i++) {
+ if (strncmp(if_name, g_interface_name_alias_map[i].if_name, IFNAMSIZ) == 0) {
+ strncpy(if_alias_out, g_interface_name_alias_map[i].if_alias, IFNAMSIZ);
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+// Frees global map g_interface_name_alias_map
+// Sets g_interface_name_alias_map_size to 0
+static void
+free_interface_alias_map(void) {
+ free(g_interface_name_alias_map);
+ g_interface_name_alias_map_size = 0;
+}

View File

@ -0,0 +1,442 @@
This patch adds the following functionality to dhcrelay in isc-dhcp v4.3.3-6:
* Add customizable Circuit ID and Remote ID fields
* Support for obtaining name of physical interfaces that are part of a bridge interface
diff -ruN a/isc-dhcp/relay/dhcrelay.c b/isc-dhcp/relay/dhcrelay.c
--- a/isc-dhcp/relay/dhcrelay.c 2017-11-17 00:36:51.575121900 +0000
+++ b/isc-dhcp/relay/dhcrelay.c 2017-11-17 00:52:51.024607833 +0000
@@ -73,6 +73,8 @@
did not match any known circuit ID. */
int missing_circuit_id = 0; /* Circuit ID option in matching RAI option
was missing. */
+const char *agent_circuit_id_fmt = NULL; /* Circuit ID custom format string. */
+const char *agent_remote_id_fmt = NULL; /* Remote ID custom format string. */
int max_hop_count = 10; /* Maximum hop count */
#ifdef DHCPv6
@@ -120,6 +122,14 @@
char *dhcrelay_sub_id = NULL;
#endif
+struct interface_name_alias_tuple {
+ char if_name[IFNAMSIZ + 1];
+ char if_alias[IFNAMSIZ + 1];
+};
+
+static struct interface_name_alias_tuple *g_interface_name_alias_map = NULL;
+static size_t g_interface_name_alias_map_size = 0;
+
static void do_relay4(struct interface_info *, struct dhcp_packet *,
unsigned int, unsigned int, struct iaddr,
struct hardware *);
@@ -132,6 +142,10 @@
struct interface_info **,
struct dhcp_packet *, unsigned);
+static int load_interface_alias_map(const char *port_alias_map_file_path);
+static int get_interface_alias_by_name(const char *if_name, char *if_alias_out);
+static void free_interface_alias_map(void);
+
static const char copyright[] =
"Copyright 2004-2015 Internet Systems Consortium.";
static const char arr[] = "All rights reserved.";
@@ -140,28 +154,41 @@
static const char url[] =
"For info, please visit https://www.isc.org/software/dhcp/";
+#define DHCRELAY_OPTION82_USAGE \
+"circuit_id/remote_id interpreted sequences are:\n" \
+"\n" \
+" %%%% A single %%\n" \
+" %%h Hostname of device\n" \
+" %%p Alias of interface that generated the request\n" \
+" %%P Hardware address of interface that generated the request\n" \
+" %%C Client hardware address\n" \
+" %%I DHCP relay agent IP Address\n" \
+
#ifdef DHCPv6
#define DHCRELAY_USAGE \
-"Usage: dhcrelay [-4] [-d] [-q] [-a] [-D]\n"\
+"Usage: dhcrelay [-4] [-d] [-q] [-a <circuit_id> <remote_id>] [-D]\n"\
" [-A <length>] [-c <hops>] [-p <port>]\n" \
" [-pf <pid-file>] [--no-pid]\n"\
" [-m append|replace|forward|discard]\n" \
+" [--name-alias-map-file <name-alias-map-file>]\n" \
" [-i interface0 [ ... -i interfaceN]\n" \
" server0 [ ... serverN]\n\n" \
" dhcrelay -6 [-d] [-q] [-I] [-c <hops>] [-p <port>]\n" \
" [-pf <pid-file>] [--no-pid]\n" \
+" [--name-alias-map-file <name-alias-map-file>]\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"
+" upper (server link): [address%%]interface\n\n" DHCRELAY_OPTION82_USAGE
#else
#define DHCRELAY_USAGE \
-"Usage: dhcrelay [-d] [-q] [-a] [-D] [-A <length>] [-c <hops>] [-p <port>]\n" \
-" [-pf <pid-file>] [--no-pid]\n" \
+"Usage: dhcrelay [-d] [-q] [-a <circuit_id> <remote_id>] [-D]\n" \
+" [-A <length>] [-c <hops>] [-p <port>]\n" \
+" [-pf <pid-file>] [--no-pid]\n"\
" [-m append|replace|forward|discard]\n" \
" [-i interface0 [ ... -i interfaceN]\n" \
-" server0 [ ... serverN]\n\n"
+" server0 [ ... serverN]\n\n" DHCRELAY_OPTION82_USAGE
#endif
static void usage() {
@@ -287,6 +314,15 @@
local_family_set = 1;
local_family = AF_INET;
#endif
+ if (++i == argc)
+ usage();
+
+ if (argv[i] != NULL && argv[i][0] != '-')
+ agent_circuit_id_fmt = argv[i++];
+
+ if (argv[i] != NULL && argv[i][0] != '-')
+ agent_remote_id_fmt = argv[i];
+
add_agent_options = 1;
} else if (!strcmp(argv[i], "-A")) {
#ifdef DHCPv6
@@ -383,6 +419,13 @@
no_dhcrelay_pid = ISC_TRUE;
} else if (!strcmp(argv[i], "--no-pid")) {
no_pid_file = ISC_TRUE;
+ } else if (!strcmp(argv[i], "--name-alias-map-file")) {
+ if (++i == argc)
+ usage();
+ if (load_interface_alias_map(argv[i]) != 0)
+ log_fatal("Failed to load interface name-alias map.");
+ path_dhcrelay_pid = argv[i];
+ no_dhcrelay_pid = ISC_TRUE;
} else if (!strcmp(argv[i], "--version")) {
log_info("isc-dhcrelay-%s", PACKAGE_VERSION);
exit(0);
@@ -602,6 +645,8 @@
dispatch();
/* In fact dispatch() never returns. */
+ free_interface_alias_map();
+
return (0);
}
@@ -690,10 +735,10 @@
&to, htop) < 0) {
++server_packet_errors;
} else {
- log_debug("Forwarded BOOTREPLY for %s to %s",
- print_hw_addr(packet->htype, packet->hlen,
- packet->chaddr),
- inet_ntoa(to.sin_addr));
+ //log_debug("Forwarded BOOTREPLY for %s to %s",
+ // print_hw_addr(packet->htype, packet->hlen,
+ // packet->chaddr),
+ // inet_ntoa(to.sin_addr));
++server_packets_relayed;
}
@@ -732,10 +777,11 @@
&sp->to, NULL) < 0) {
++client_packet_errors;
} else {
- log_debug("Forwarded BOOTREQUEST for %s to %s",
- print_hw_addr(packet->htype, packet->hlen,
- packet->chaddr),
- inet_ntoa(sp->to.sin_addr));
+ //log_debug("Forwarded BOOTREQUEST for %s to %s",
+ // print_hw_addr(packet->htype, packet->hlen,
+ // packet->chaddr),
+ // inet_ntoa(sp->to.sin_addr));
+
++client_packets_relayed;
}
}
@@ -937,6 +983,151 @@
return (-1);
}
+static int
+_bridgefdbquery(const char *hwAddr, char *interface, int *vlanid) {
+
+#define xstr(s) str(s)
+#define str(s) #s
+#define FDB_STRING_LEN 100
+#define FDB_BUFFER_LEN (FDB_STRING_LEN + 1)
+
+/*
+ * Format for sscanf() to read the 1st, 3th, and 5th
+ * space-delimited fields
+ *
+ * bridge fdb show output
+ * 6c:64:1a:00:06:13 dev swp35 vlan 0 master bridge permanent
+ */
+#define FDB_LINE_FORMAT "%" xstr(FDB_STRING_LEN) "s %*s " \
+ "%" xstr(FDB_STRING_LEN) "s %*s %d %*s"
+
+ char cmdstr[FDB_BUFFER_LEN];
+ char buf[FDB_BUFFER_LEN];
+ char macAddr[FDB_BUFFER_LEN];
+
+ if ((interface == NULL) || (vlanid == NULL)) {
+ return 0;
+ }
+ sprintf(cmdstr, "bridge fdb show | grep -m 1 %s", hwAddr);
+ FILE *cmd = popen(cmdstr, "r");
+
+ if (cmd != NULL) {
+ while (fgets(buf, sizeof(buf), cmd)) {
+ sscanf(buf, FDB_LINE_FORMAT, macAddr, interface, vlanid);
+ //log_debug("bridgefdbquery: macAddr:%s interface: %s vlanid %d",
+ // macAddr, interface, *vlanid);
+ }
+ pclose(cmd);
+ return 0;
+ }
+
+ return -1;
+}
+
+/*
+ * Format the message that will be used by circuit_id and remote_id
+ */
+static int
+format_relay_agent_rfc3046_msg(struct interface_info *ip, struct dhcp_packet *packet,
+ const char *format, char *msg, size_t msgn) {
+ size_t len = 0;
+ char hostname[HOST_NAME_MAX + 1] = { 0 };
+ char ifname[IFNAMSIZ + 1] = { 0 };
+ char *buf = msg;
+
+ for ( ; format && *format && len < msgn; ++format) {
+ size_t strn = 0;
+ const char *str = NULL;
+
+ if (*format == '%') {
+ switch (*++format) {
+ case '\0':
+ --format;
+ break;
+
+ case '%': /* A literal '%' */
+ str = "%";
+ break;
+
+ case 'h': /* Hostname */
+ gethostname(hostname, HOST_NAME_MAX);
+ str = hostname;
+ break;
+
+ case 'p': /* Name of interface that we received the request from */
+ /*
+ * Query FDB to identify the exact physical interface only when source MAC address
+ * is present and '20: DHCP relay agent IP address' (giaddr) is not present
+ */
+ if (packet->htype && !packet->giaddr.s_addr) {
+ int ret = 0, vlanid = 0;
+
+ ret = _bridgefdbquery(print_hw_addr(packet->htype, packet->hlen, packet->chaddr),
+ ip->name,
+ &vlanid);
+
+ if (ret < 0) {
+ //log_debug("MAC Address: %s (interface:%s vlan:%d) not found in bridge fdb show",
+ // print_hw_addr (packet->htype, packet->hlen, packet->chaddr),
+ // ip->name,
+ // vlanid);
+
+ strncpy(ifname, ip->name, IFNAMSIZ);
+ }
+ else if (strlen(ip->name) > 0) {
+ // Translate SONiC interface name to vendor alias
+ if (get_interface_alias_by_name(ip->name, ifname) < 0) {
+ log_error("Failed to retrieve alias for interface name '%s'. Defaulting to interface name.", ip->name);
+ strncpy(ifname, ip->name, IFNAMSIZ);
+ }
+
+ //log_debug("Mapped interface name '%s' to alias '%s'", ip->name, ifname);
+
+ //log_debug("Adding option 82 interface alias for MAC Address %s as '%s'",
+ // print_hw_addr (packet->htype, packet->hlen, packet->chaddr),
+ // ifname);
+ }
+
+ str = ifname;
+ }
+ break;
+
+ case 'P': /* Physical address of interface that we received the request from */
+ str = print_hw_addr(ip->hw_address.hbuf[0], ip->hw_address.hlen - 1, &ip->hw_address.hbuf[1]);
+ break;
+
+ case 'C': /* 24: Client hardware address */
+ str = print_hw_addr(packet->htype, packet->hlen, packet->chaddr);
+ break;
+
+ case 'I': /* 20: DHCP relay agent IP address */
+ str = inet_ntoa(packet->giaddr);
+ break;
+
+ default:
+ log_error("Option %%%c is unrecognized and will not be formatted!", *format);
+ continue;
+ }
+
+ if (str)
+ strn = strlen(str);
+ } else {
+ str = format;
+ strn += 1;
+ }
+
+ // Do we have room?
+ if ((strn+len) > msgn) {
+ return 0;
+ }
+
+ memcpy(buf+len, str, strn);
+ len += strn;
+ }
+
+ return len;
+}
+
/*
* Examine a packet to see if it's a candidate to have a Relay
* Agent Information option tacked onto its tail. If it is, tack
@@ -948,6 +1139,8 @@
int is_dhcp = 0, mms;
unsigned optlen;
u_int8_t *op, *nextop, *sp, *max, *end_pad = NULL;
+ char circuit_id_buf[255] = { '\0', };
+ char remote_id_buf[255] = { '\0', };
/* If we're not adding agent options to packets, we can skip
this. */
@@ -1077,6 +1270,38 @@
op = sp;
#endif
+ /* option82: custom string for circuit_id */
+ if (agent_circuit_id_fmt) {
+ size_t len = 0;
+
+ len = format_relay_agent_rfc3046_msg(ip, packet, agent_circuit_id_fmt,
+ circuit_id_buf, sizeof(circuit_id_buf));
+
+ if (len > 0) {
+ ip->circuit_id = (uint8_t *)circuit_id_buf;
+ ip->circuit_id_len = len;
+
+ //log_debug("Sending on %s option82:circuit_id='%s' (%d)",
+ // ip->name, (char *)ip->circuit_id, ip->circuit_id_len);
+ }
+ }
+
+ /* option82: custom string for remote_id */
+ if (agent_remote_id_fmt) {
+ size_t len = 0;
+
+ len = format_relay_agent_rfc3046_msg(ip, packet, agent_remote_id_fmt,
+ remote_id_buf, sizeof(remote_id_buf));
+
+ if (len > 0) {
+ ip->remote_id = (uint8_t *)remote_id_buf;
+ ip->remote_id_len = len;
+
+ //log_debug("Sending on %s option82:remote_id='%s' (%d)",
+ // ip->name, (char *)ip->remote_id, ip->remote_id_len);
+ }
+ }
+
/* Sanity check. Had better not ever happen. */
if ((ip->circuit_id_len > 255) ||(ip->circuit_id_len < 1))
log_fatal("Circuit ID length %d out of range [1-255] on "
@@ -1102,7 +1327,7 @@
* If not, forward without adding the option.
*/
if (max - sp >= optlen + 3) {
- log_debug("Adding %d-byte relay agent option", optlen + 3);
+ //log_debug("Adding %d-byte relay agent option", optlen + 3);
/* Okay, cons up *our* Relay Agent Information option. */
*sp++ = DHO_DHCP_AGENT_OPTIONS;
@@ -1735,3 +1960,73 @@
exit(0);
}
+
+#define MAX_PORT_CONFIG_LINE_LEN 1024
+
+// Allocates and loads global map g_interface_name_alias_map
+// Also sets global g_interface_name_alias_map_size
+static int
+load_interface_alias_map(const char *port_alias_map_file_path) {
+ int i = 0;
+ FILE *fp = NULL;
+ char line[MAX_PORT_CONFIG_LINE_LEN] = { 0 };
+
+ fp = fopen(port_alias_map_file_path,"r");
+ if (fp == NULL) {
+ log_error("Unable to open %s", port_alias_map_file_path);
+ return -1;
+ }
+
+ g_interface_name_alias_map_size = 0;
+
+ // Count the number of interfaces listed in the file
+ while (fgets(line, sizeof(line), fp)) {
+ g_interface_name_alias_map_size++;
+ }
+
+ // Allocate our map accordingly
+ g_interface_name_alias_map = ((struct interface_name_alias_tuple *)
+ dmalloc((sizeof(struct interface_name_alias_tuple) * g_interface_name_alias_map_size),
+ MDL));
+
+ // Reset file position indicator to beginning of file
+ fseek(fp, 0, SEEK_SET);
+
+ // Every line should contain exactly one name-alias pair
+ while (fgets(line, sizeof(line), fp)) {
+ // Each line should read as "<name><whitespace><alias>"
+ sscanf(line, "%s %s", g_interface_name_alias_map[i].if_name, g_interface_name_alias_map[i].if_alias);
+ i++;
+ }
+
+ fclose(fp);
+
+ log_info("Loaded %d interface name-alias mappings", i);
+
+ return 0;
+}
+
+// Locates alias for port named if_name, copies alias into if_alias_out, up to a
+// max of IFNAMSIZ bytes.
+// Returns 0 on success, -1 on failure
+static int
+get_interface_alias_by_name(const char *if_name, char *if_alias_out) {
+ int i = 0;
+
+ for (i = 0; i < g_interface_name_alias_map_size; i++) {
+ if (strncmp(if_name, g_interface_name_alias_map[i].if_name, IFNAMSIZ) == 0) {
+ strncpy(if_alias_out, g_interface_name_alias_map[i].if_alias, IFNAMSIZ);
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+// Frees global map g_interface_name_alias_map
+// Sets g_interface_name_alias_map_size to 0
+static void
+free_interface_alias_map(void) {
+ free(g_interface_name_alias_map);
+ g_interface_name_alias_map_size = 0;
+}