mirror of
https://github.com/opnsense/src.git
synced 2026-06-09 08:43:19 -04:00
dhclient: VLAN priority support
These changes are based on the dhclient used in pfSense 2.3, which
seems not to have made it into FreeBSD 11 as used in pfSense 2.4.
To be able to add a VLAN priority to a DHCP request the following
must be added to the config:
interface "em1_vlan123" {
vlan-parent "em1";
vlan-id 123;
vlan-pcp 6;
}
Extensive (and annoying) care has been taken WRT keeping the BPF
write filter functional for security reasons.
Based on a submission by Martin Wasley <martin@queens-park.com>.
This commit is contained in:
parent
8821bf2f1a
commit
b7307744e0
8 changed files with 105 additions and 19 deletions
|
|
@ -3,6 +3,7 @@
|
|||
/* BPF socket interface code, originally contributed by Archie Cobbs. */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2018 Franco Fichtner <franco@opnsense.org>
|
||||
* Copyright (c) 1995, 1996, 1998, 1999
|
||||
* The Internet Software Consortium. All rights reserved.
|
||||
*
|
||||
|
|
@ -94,23 +95,40 @@ if_register_bpf(struct interface_info *info, int flags)
|
|||
* 'ip and udp and src port bootps and dst port (bootps or bootpc)'
|
||||
*/
|
||||
struct bpf_insn dhcp_bpf_wfilter[] = {
|
||||
/* Set packet index for IP packet... */
|
||||
BPF_STMT(BPF_LDX + BPF_W + BPF_IMM, 0),
|
||||
|
||||
/* Test whether this is a VLAN packet... */
|
||||
BPF_STMT(BPF_LD + BPF_H + BPF_IND, 12),
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_VLAN, 0, 1),
|
||||
|
||||
/* Correct the packet index for VLAN... */
|
||||
BPF_STMT(BPF_LDX + BPF_W + BPF_IMM, 4),
|
||||
|
||||
/* Make sure it is an IPv4 packet... */
|
||||
BPF_STMT(BPF_LD + BPF_B + BPF_IND, 14),
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, (IPVERSION << 4) + 5, 0, 12),
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, (IPVERSION << 4) + 5, 0, 18),
|
||||
|
||||
/* 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),
|
||||
BPF_STMT(BPF_LD + BPF_H + BPF_IND, 12),
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 16),
|
||||
|
||||
/* 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),
|
||||
BPF_STMT(BPF_LD + BPF_B + BPF_IND, 23),
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 14),
|
||||
|
||||
/* 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), /* patched */
|
||||
BPF_STMT(BPF_LD + BPF_H + BPF_IND, 20),
|
||||
BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 12, 0), /* patched */
|
||||
|
||||
/* Get the IP header length... */
|
||||
BPF_STMT(BPF_MISC + BPF_TXA, 0),
|
||||
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 2),
|
||||
BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14),
|
||||
BPF_JUMP(BPF_JMP + BPF_JA, 1, 0, 0),
|
||||
BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 18),
|
||||
BPF_STMT(BPF_ALU + BPF_ADD + BPF_X, 0),
|
||||
BPF_STMT(BPF_MISC + BPF_TAX, 0),
|
||||
|
||||
/* Make sure it's from the right port... */
|
||||
BPF_STMT(BPF_LD + BPF_H + BPF_IND, 14),
|
||||
|
|
@ -152,8 +170,8 @@ if_register_send(struct interface_info *info)
|
|||
p.bf_len = dhcp_bpf_wfilter_len;
|
||||
p.bf_insns = dhcp_bpf_wfilter;
|
||||
|
||||
if (dhcp_bpf_wfilter[7].k == 0x1fff)
|
||||
dhcp_bpf_wfilter[7].k = htons(IP_MF|IP_OFFMASK);
|
||||
if (dhcp_bpf_wfilter[11].k == 0x1fff)
|
||||
dhcp_bpf_wfilter[11].k = htons(IP_MF|IP_OFFMASK);
|
||||
|
||||
if (ioctl(info->wfdesc, BIOCSETWF, &p) < 0)
|
||||
error("Can't install write filter program: %m");
|
||||
|
|
|
|||
|
|
@ -75,6 +75,9 @@ read_client_conf(void)
|
|||
memset(&top_level_config, 0, sizeof(top_level_config));
|
||||
|
||||
/* Set some defaults... */
|
||||
top_level_config.vlan_id = 0;
|
||||
top_level_config.vlan_pcp = 0;
|
||||
top_level_config.vlan_parent = NULL;
|
||||
top_level_config.timeout = 60;
|
||||
top_level_config.select_interval = 0;
|
||||
top_level_config.reboot_timeout = 10;
|
||||
|
|
@ -198,6 +201,7 @@ parse_client_statement(FILE *cfile, struct interface_info *ip,
|
|||
int token;
|
||||
char *val;
|
||||
struct option *option;
|
||||
time_t tmp;
|
||||
|
||||
switch (next_token(&val, cfile)) {
|
||||
case SEND:
|
||||
|
|
@ -257,6 +261,17 @@ parse_client_statement(FILE *cfile, struct interface_info *ip,
|
|||
case REBOOT:
|
||||
parse_lease_time(cfile, &config->reboot_timeout);
|
||||
return;
|
||||
case VLAN_ID:
|
||||
parse_lease_time(cfile, &tmp);
|
||||
config->vlan_id = (int)tmp;
|
||||
return;
|
||||
case VLAN_PARENT:
|
||||
config->vlan_parent = parse_string(cfile);
|
||||
return;
|
||||
case VLAN_PCP:
|
||||
parse_lease_time(cfile, &tmp);
|
||||
config->vlan_pcp = (int)tmp;
|
||||
return;
|
||||
case BACKOFF_CUTOFF:
|
||||
parse_lease_time(cfile, &config->backoff_cutoff);
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -519,6 +519,12 @@ intern(char *atom, int dfv)
|
|||
case 'v':
|
||||
if (!strcasecmp(atom + 1, "endor-class"))
|
||||
return (VENDOR_CLASS);
|
||||
if (!strcasecmp(atom + 1, "lan-id"))
|
||||
return (VLAN_ID);
|
||||
if (!strcasecmp(atom + 1, "lan-parent"))
|
||||
return (VLAN_PARENT);
|
||||
if (!strcasecmp(atom + 1, "lan-pcp"))
|
||||
return (VLAN_PCP);
|
||||
break;
|
||||
case 'y':
|
||||
if (!strcasecmp(atom + 1, "iaddr"))
|
||||
|
|
|
|||
|
|
@ -437,6 +437,23 @@ script, and expiry times are ignored.
|
|||
A typical alias declaration includes an interface declaration, a fixed-address
|
||||
declaration for the IP alias address, and a subnet-mask option declaration.
|
||||
A medium statement should never be included in an alias declaration.
|
||||
.Sh VLAN DECLARATIONS
|
||||
In order to be able to send a request using a specific VLAN PCP all of the
|
||||
following options are required to emit a properly formed frame.
|
||||
.Bl -tag -width indent
|
||||
.It Ic vlan-parent Qo Ar interface Qc ;
|
||||
The
|
||||
.Ic vlan-parent
|
||||
allows attaching to the parent interface of the VLAN.
|
||||
.It Ic vlan-id Ar identifier ;
|
||||
The
|
||||
.Ic vlan-id
|
||||
sets the desired indentifier of the VLAN.
|
||||
.It Ic vlan-pcp Ar priority ;
|
||||
The
|
||||
.Ic vlan-pcp
|
||||
sets the desired priority code point value of the VLAN.
|
||||
.El
|
||||
.Sh OTHER DECLARATIONS
|
||||
.Bl -tag -width indent
|
||||
.It Ic reject Ar ip-address ;
|
||||
|
|
|
|||
|
|
@ -154,6 +154,9 @@ struct client_config {
|
|||
u_int8_t required_options[256];
|
||||
u_int8_t requested_options[256];
|
||||
int requested_option_count;
|
||||
int vlan_id;
|
||||
int vlan_pcp;
|
||||
char *vlan_parent;
|
||||
time_t timeout;
|
||||
time_t initial_interval;
|
||||
time_t retry_interval;
|
||||
|
|
|
|||
|
|
@ -129,6 +129,9 @@
|
|||
#define AUTHORITATIVE 333
|
||||
#define TOKEN_NOT 334
|
||||
#define ALWAYS_REPLY_RFC1048 335
|
||||
#define VLAN_ID 336
|
||||
#define VLAN_PCP 337
|
||||
#define VLAN_PARENT 338
|
||||
|
||||
#define is_identifier(x) ((x) >= FIRST_TOKEN && \
|
||||
(x) != STRING && \
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ static int interface_status(struct interface_info *ifinfo);
|
|||
void
|
||||
discover_interfaces(struct interface_info *iface)
|
||||
{
|
||||
char *pname = iface->client->config->vlan_parent;
|
||||
struct ifaddrs *ifap, *ifa;
|
||||
struct sockaddr_in foo;
|
||||
struct ifreq *tif;
|
||||
|
|
@ -124,7 +125,20 @@ discover_interfaces(struct interface_info *iface)
|
|||
|
||||
/* Register the interface... */
|
||||
if_register_receive(iface);
|
||||
if_register_send(iface);
|
||||
if (pname != NULL) {
|
||||
char rname[IFNAMSIZ];
|
||||
|
||||
/* Change interface name for bpf registration */
|
||||
strlcpy(rname, iface->name, IFNAMSIZ);
|
||||
strlcpy(iface->ifp->ifr_name, pname, IFNAMSIZ);
|
||||
|
||||
if_register_send(iface);
|
||||
|
||||
/* Change name back to original */
|
||||
strlcpy(iface->ifp->ifr_name, rname, IFNAMSIZ);
|
||||
} else {
|
||||
if_register_send(iface);
|
||||
}
|
||||
add_protocol(iface->name, iface->rfdesc, got_one, iface);
|
||||
freeifaddrs(ifap);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -92,19 +92,29 @@ void
|
|||
assemble_hw_header(struct interface_info *interface, unsigned char *buf,
|
||||
int *bufix)
|
||||
{
|
||||
struct ether_header eh;
|
||||
int vlpcp = interface->client->config->vlan_pcp;
|
||||
int vlid = interface->client->config->vlan_id;
|
||||
int plen = ETHER_HEADER_SIZE;
|
||||
struct ether_vlan_header eh;
|
||||
|
||||
memset(eh.ether_dhost, 0xff, sizeof(eh.ether_dhost));
|
||||
if (interface->hw_address.hlen == sizeof(eh.ether_shost))
|
||||
memcpy(eh.ether_shost, interface->hw_address.haddr,
|
||||
sizeof(eh.ether_shost));
|
||||
memset(eh.evl_dhost, 0xff, sizeof(eh.evl_dhost));
|
||||
if (interface->hw_address.hlen == sizeof(eh.evl_shost))
|
||||
memcpy(eh.evl_shost, interface->hw_address.haddr,
|
||||
sizeof(eh.evl_shost));
|
||||
else
|
||||
memset(eh.ether_shost, 0x00, sizeof(eh.ether_shost));
|
||||
memset(eh.evl_shost, 0x00, sizeof(eh.evl_shost));
|
||||
|
||||
eh.ether_type = htons(ETHERTYPE_IP);
|
||||
eh.evl_encap_proto = htons(ETHERTYPE_IP);
|
||||
|
||||
memcpy(&buf[*bufix], &eh, ETHER_HEADER_SIZE);
|
||||
*bufix += ETHER_HEADER_SIZE;
|
||||
if (vlid != 0) {
|
||||
eh.evl_tag = htons(EVL_MAKETAG(vlid, vlpcp, 0));
|
||||
eh.evl_encap_proto = htons(ETHERTYPE_VLAN);
|
||||
eh.evl_proto = htons(ETHERTYPE_IP);
|
||||
plen += ETHER_VLAN_ENCAP_LEN;
|
||||
}
|
||||
|
||||
memcpy(&buf[*bufix], &eh, plen);
|
||||
*bufix += plen;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
Loading…
Reference in a new issue