From: "Peter J. Philipp" Subject: an update to the bridge(4) inspection of pppoe patch To: tech@openbsd.org Cc: pjp@delphinusdns.org Date: Fri, 2 Feb 2024 11:45:28 +0100 A slight update, after visually spotting a bug and then testing it again. bridge0: flags=41 mtu 1500 index 4 llprio 3 groups: bridge priority 32768 hellotime 2 fwddelay 15 maxage 20 holdcnt 6 proto rstp designated: id 00:00:00:00:00:00 priority 0 port 5 ifpriority 0 ifcost 0 bse0 flags=3 port 1 ifpriority 0 ifcost 0 pass in on bse0 src 00:11:22:33:44:55 dst 00:11:ff:ff:00:01 tag PPPOE pppoe sessid 1 Addresses (max cache: 100, timeout: 240): fe:e1:ba:d0:eb:58 bse0 1 flags=0<> 00:11:22:33:44:55 bse0 1 flags=0<> .... root@vega# tcpdump -v -n -i pflog0 -s 1000 -X -c1 -e tcpdump: listening on pflog0, link-type PFLOG 11:41:29.976376 rule 18/(match) [uid 0, pid 53550] block in on bse0: 192.168.177.99.1212 > 192.168.177.255.22: [udp sum ok] udp 10 (DF) (ttl 255, id 23233, len 38) 0000: 4500 0026 5ac1 4000 ff11 3c51 c0a8 b163 E..&Z.@...ifbr_arpf.brla_flags & BRLA_TPA) printf(" tpa %s", inet_ntoa(r->ifbr_arpf.brla_tpa)); + if (r->ifbr_pppoef.brla_flags & BRLA_PPPOE) { + printf(" pppoe"); + + if (r->ifbr_pppoef.brla_flags & BRLA_PPPOESESS) + printf(" sessid %u", r->ifbr_pppoef.brla_session); + } + printf("\n"); } @@ -1005,6 +1013,11 @@ bridge_rule(int targc, char **targv, int argc--; argv++; if (bridge_arprule(&rule, &argc, &argv) == -1) goto bad_rule; + } else if (strcmp(argv[0], "pppoe") == 0) { + rule.ifbr_pppoef.brla_flags |= BRLA_PPPOE; + argc--; argv++; + if (bridge_pppoerule(&rule, &argc, &argv) == -1) + goto bad_rule; } else goto bad_rule; @@ -1030,6 +1043,30 @@ bridge_rule(int targc, char **targv, int bad_rule: bridge_badrule(targc, targv, ln); return (1); +} + + +int +bridge_pppoerule(struct ifbrlreq *rule, int *argc, char ***argv) +{ + while (*argc) { + u_short *sess; + + if (strcmp((*argv)[0], "sessid") == 0) { + sess = &rule->ifbr_pppoef.brla_session; + } else + return (0); + + (*argc)--; (*argv)++; + if (sess != NULL) { + if (*argc == 0) + return (-1); + *sess = atoi((*argv)[0]); + rule->ifbr_pppoef.brla_flags |= BRLA_PPPOESESS; + (*argc)--; (*argv)++; + } + } + return (0); } int Index: sbin/ifconfig/ifconfig.8 =================================================================== RCS file: /cvs/src/sbin/ifconfig/ifconfig.8,v retrieving revision 1.399 diff -u -p -u -r1.399 ifconfig.8 --- sbin/ifconfig/ifconfig.8 11 Jan 2024 17:22:04 -0000 1.399 +++ sbin/ifconfig/ifconfig.8 2 Feb 2024 10:30:07 -0000 @@ -801,6 +801,12 @@ like a hub or a wireless network. .Op Cm tpa Ar ipaddr .Oc .Ek +.Bk -words +.Oo +.Cm pppoe +.Op Cm sessid Ar integer +.Oc +.Ek .Xc Add a filtering rule to an interface. Rules have a similar syntax to those in Index: sys/net/bridgectl.c =================================================================== RCS file: /cvs/src/sys/net/bridgectl.c,v retrieving revision 1.25 diff -u -p -u -r1.25 bridgectl.c --- sys/net/bridgectl.c 25 Feb 2021 02:48:21 -0000 1.25 +++ sys/net/bridgectl.c 2 Feb 2024 10:30:15 -0000 @@ -48,6 +48,9 @@ #include #include +#include +#include + #include @@ -623,6 +626,7 @@ bridge_brlconf(struct bridge_iflist *bif req->ifbr_src = n->brl_src; req->ifbr_dst = n->brl_dst; req->ifbr_arpf = n->brl_arpf; + req->ifbr_pppoef = n->brl_pppoef; #if NPF > 0 req->ifbr_tagname[0] = '\0'; if (n->brl_tag) @@ -642,6 +646,7 @@ bridge_brlconf(struct bridge_iflist *bif req->ifbr_src = n->brl_src; req->ifbr_dst = n->brl_dst; req->ifbr_arpf = n->brl_arpf; + req->ifbr_pppoef = n->brl_pppoef; #if NPF > 0 req->ifbr_tagname[0] = '\0'; if (n->brl_tag) @@ -658,6 +663,27 @@ done: } u_int8_t +bridge_pppoesfilter(struct brl_node *n, struct ether_header *eh, struct mbuf *m) +{ + struct pppoehdr hdr; + + if (!(n->brl_pppoef.brla_flags & (BRLA_PPPOE))) + return (1); + + if (m->m_pkthdr.len < (ETHER_HDR_LEN + sizeof(hdr) + sizeof(u_int16_t))) + return (0); /* log error? */ + + m_copydata(m, ETHER_HDR_LEN, sizeof(hdr), &hdr); + + if ((ntohs(hdr.session) != n->brl_pppoef.brla_session) && + (n->brl_pppoef.brla_flags & BRLA_PPPOESESS)) { + return (0); + } + + return (1); +} + +u_int8_t bridge_arpfilter(struct brl_node *n, struct ether_header *eh, struct mbuf *m) { struct ether_arp ea; @@ -665,10 +691,9 @@ bridge_arpfilter(struct brl_node *n, str if (!(n->brl_arpf.brla_flags & (BRLA_ARP|BRLA_RARP))) return (1); - if (ntohs(eh->ether_type) != ETHERTYPE_ARP) - return (0); if (m->m_pkthdr.len < ETHER_HDR_LEN + sizeof(ea)) return (0); /* log error? */ + m_copydata(m, ETHER_HDR_LEN, sizeof(ea), &ea); if (ntohs(ea.arp_hrd) != ARPHRD_ETHER || @@ -706,15 +731,57 @@ u_int8_t bridge_filterrule(struct brl_head *h, struct ether_header *eh, struct mbuf *m) { struct brl_node *n; + struct llc llc; u_int8_t action, flags; + u_int16_t etype; if (SIMPLEQ_EMPTY(h)) return (BRL_ACTION_PASS); KERNEL_LOCK(); SIMPLEQ_FOREACH(n, h, brl_next) { - if (!bridge_arpfilter(n, eh, m)) - continue; + switch (etype = ntohs(eh->ether_type)) { + case ETHERTYPE_ARP: /* FALLTHROUGH */ + case ETHERTYPE_REVARP: + if (!bridge_arpfilter(n, eh, m)) + continue; + break; + case ETHERTYPE_PPPOE: + if (!bridge_pppoesfilter(n, eh, m)) + continue; + break; + default: + /* check if we have a Logical Link Control header */ + if ((etype <= ETHERMTU || + m->m_pkthdr.len >= (LLC_SNAPFRAMELEN + + ETHER_HDR_LEN))) { + + m_copydata(m, ETHER_HDR_LEN, LLC_SNAPFRAMELEN, + &llc); + + if (llc.llc_dsap != LLC_SNAP_LSAP || + llc.llc_ssap != LLC_SNAP_LSAP || + llc.llc_control != LLC_UI || + llc.llc_snap.org_code[0] || + llc.llc_snap.org_code[1] || + llc.llc_snap.org_code[2]) + continue; + + etype = ntohs(llc.llc_snap.ether_type); + + if ((etype == ETHERTYPE_ARP || + etype == ETHERTYPE_REVARP) && + !bridge_arpfilter(n, eh, m)) + continue; + + if ((etype == ETHERTYPE_PPPOE) && + !bridge_pppoesfilter(n, eh, m)) + continue; + } + + break; + } + flags = n->brl_flags & (BRL_FLAG_SRCVALID|BRL_FLAG_DSTVALID); if (flags == 0) goto return_action; @@ -765,6 +832,7 @@ bridge_addrule(struct bridge_iflist *bif n->brl_action = req->ifbr_action; n->brl_flags = req->ifbr_flags; n->brl_arpf = req->ifbr_arpf; + n->brl_pppoef = req->ifbr_pppoef; #if NPF > 0 if (req->ifbr_tagname[0]) n->brl_tag = pf_tagname2tag(req->ifbr_tagname, 1); Index: sys/net/if_bridge.c =================================================================== RCS file: /cvs/src/sys/net/if_bridge.c,v retrieving revision 1.368 diff -u -p -u -r1.368 if_bridge.c --- sys/net/if_bridge.c 16 May 2023 14:32:54 -0000 1.368 +++ sys/net/if_bridge.c 2 Feb 2024 10:30:15 -0000 @@ -48,6 +48,8 @@ #include #include #include +#include +#include #include #include @@ -1668,11 +1670,16 @@ struct mbuf * bridge_ip(struct ifnet *brifp, int dir, struct ifnet *ifp, struct ether_header *eh, struct mbuf *m) { - struct llc llc; int hassnap = 0; - struct ip *ip; + int haspppoe = 0; int hlen; - u_int16_t etype; + int llclen = ETHER_HDR_LEN; + + u_int16_t etype, lcp; + + struct ip *ip; + struct llc llc; + struct pppoehdr phdr; #if NVLAN > 0 if (m->m_flags & M_VLANTAG) @@ -1681,7 +1688,8 @@ bridge_ip(struct ifnet *brifp, int dir, etype = ntohs(eh->ether_type); - if (etype != ETHERTYPE_IP && etype != ETHERTYPE_IPV6) { + if ((etype != ETHERTYPE_IP) && (etype != ETHERTYPE_IPV6) && + (etype != ETHERTYPE_PPPOE)) { if (etype > ETHERMTU || m->m_pkthdr.len < (LLC_SNAPFRAMELEN + ETHER_HDR_LEN)) @@ -1698,17 +1706,42 @@ bridge_ip(struct ifnet *brifp, int dir, return (m); etype = ntohs(llc.llc_snap.ether_type); - if (etype != ETHERTYPE_IP && etype != ETHERTYPE_IPV6) + if (etype != ETHERTYPE_IP && etype != ETHERTYPE_IPV6 && + etype != ETHERTYPE_PPPOE) return (m); + hassnap = 1; } + if (etype == ETHERTYPE_PPPOE) { + if (hassnap) { + llclen += LLC_SNAPFRAMELEN; + } + + m_copydata(m, llclen, sizeof(phdr), &phdr); + llclen += sizeof(phdr); + + m_copydata(m, llclen, sizeof(u_int16_t), &lcp); + + if (ntohs(lcp) == PPP_IP) + etype = ETHERTYPE_IP; + else if (ntohs(lcp) == PPP_IPV6) + etype = ETHERTYPE_IPV6; + else + return (m); + + haspppoe = 1; + } + + m_adj(m, ETHER_HDR_LEN); + if (hassnap) m_adj(m, LLC_SNAPFRAMELEN); + if (haspppoe) + m_adj(m, sizeof(phdr) + sizeof(u_int16_t)); switch (etype) { - case ETHERTYPE_IP: m = ipv4_check(ifp, m); if (m == NULL) @@ -1793,11 +1826,29 @@ bridge_ip(struct ifnet *brifp, int dir, break; } - /* Reattach SNAP header */ + /* Reattach PPPoE and SNAP headers */ + if (haspppoe) { + u_int16_t *tmplcp; + + M_PREPEND(m, sizeof(u_int16_t), M_DONTWAIT); + if (m == NULL) + goto dropit; + + tmplcp = (u_int16_t *)mtod(m, caddr_t); + *tmplcp = lcp; + + M_PREPEND(m, sizeof(phdr), M_DONTWAIT); + if (m == NULL) + goto dropit; + + bcopy(&phdr, mtod(m, caddr_t), sizeof(phdr)); + } + if (hassnap) { M_PREPEND(m, LLC_SNAPFRAMELEN, M_DONTWAIT); if (m == NULL) goto dropit; + bcopy(&llc, mtod(m, caddr_t), LLC_SNAPFRAMELEN); } Index: sys/net/if_bridge.h =================================================================== RCS file: /cvs/src/sys/net/if_bridge.h,v retrieving revision 1.73 diff -u -p -u -r1.73 if_bridge.h --- sys/net/if_bridge.h 11 Nov 2021 10:03:10 -0000 1.73 +++ sys/net/if_bridge.h 2 Feb 2024 10:30:15 -0000 @@ -208,6 +208,14 @@ struct ifbrarpf { #define BRLA_THA 0x40 #define BRLA_TPA 0x80 +struct ifbrpppoef { + u_int16_t brla_flags; + u_int16_t brla_session; +}; + +#define BRLA_PPPOE 0x100 +#define BRLA_PPPOESESS 0x200 + struct ifbrlreq { char ifbr_name[IFNAMSIZ]; /* bridge ifs name */ char ifbr_ifsname[IFNAMSIZ]; /* member ifs name */ @@ -217,6 +225,7 @@ struct ifbrlreq { struct ether_addr ifbr_dst; /* destination mac */ char ifbr_tagname[PF_TAG_NAME_SIZE]; /* pf tagname */ struct ifbrarpf ifbr_arpf; /* arp filter */ + struct ifbrpppoef ifbr_pppoef; /* pppoe ses filter */ }; #define BRL_ACTION_BLOCK 0x01 /* block frame */ #define BRL_ACTION_PASS 0x02 /* pass frame */ @@ -286,6 +295,7 @@ struct brl_node { u_int8_t brl_action; /* what to do with match */ u_int8_t brl_flags; /* comparison flags */ struct ifbrarpf brl_arpf; /* arp filter */ + struct ifbrpppoef brl_pppoef; /* pppoe sess filter */ }; struct bstp_timer { Index: sys/net/if_pppoe.c =================================================================== RCS file: /cvs/src/sys/net/if_pppoe.c,v retrieving revision 1.83 diff -u -p -u -r1.83 if_pppoe.c --- sys/net/if_pppoe.c 14 Jul 2022 11:03:15 -0000 1.83 +++ sys/net/if_pppoe.c 2 Feb 2024 10:30:15 -0000 @@ -59,61 +59,6 @@ #define PPPOEDEBUG(a) ((sc->sc_sppp.pp_if.if_flags & IFF_DEBUG) ? printf a : 0) -struct pppoehdr { - u_int8_t vertype; - u_int8_t code; - u_int16_t session; - u_int16_t plen; -} __packed; - -struct pppoetag { - u_int16_t tag; - u_int16_t len; -} __packed; - -#define PPPOE_HEADERLEN sizeof(struct pppoehdr) -#define PPPOE_OVERHEAD (PPPOE_HEADERLEN + 2) -#define PPPOE_VERTYPE 0x11 /* VER=1, TYPE = 1 */ - -#define PPPOE_TAG_EOL 0x0000 /* end of list */ -#define PPPOE_TAG_SNAME 0x0101 /* service name */ -#define PPPOE_TAG_ACNAME 0x0102 /* access concentrator name */ -#define PPPOE_TAG_HUNIQUE 0x0103 /* host unique */ -#define PPPOE_TAG_ACCOOKIE 0x0104 /* AC cookie */ -#define PPPOE_TAG_VENDOR 0x0105 /* vendor specific */ -#define PPPOE_TAG_RELAYSID 0x0110 /* relay session id */ -#define PPPOE_TAG_MAX_PAYLOAD 0x0120 /* RFC 4638 max payload */ -#define PPPOE_TAG_SNAME_ERR 0x0201 /* service name error */ -#define PPPOE_TAG_ACSYS_ERR 0x0202 /* AC system error */ -#define PPPOE_TAG_GENERIC_ERR 0x0203 /* generic error */ - -#define PPPOE_CODE_PADI 0x09 /* Active Discovery Initiation */ -#define PPPOE_CODE_PADO 0x07 /* Active Discovery Offer */ -#define PPPOE_CODE_PADR 0x19 /* Active Discovery Request */ -#define PPPOE_CODE_PADS 0x65 /* Active Discovery Session confirmation */ -#define PPPOE_CODE_PADT 0xA7 /* Active Discovery Terminate */ - -/* two byte PPP protocol discriminator, then IP data */ -#define PPPOE_MTU (ETHERMTU - PPPOE_OVERHEAD) -#define PPPOE_MAXMTU PP_MAX_MRU - -/* Add a 16 bit unsigned value to a buffer pointed to by PTR */ -#define PPPOE_ADD_16(PTR, VAL) \ - *(PTR)++ = (VAL) / 256; \ - *(PTR)++ = (VAL) % 256 - -/* Add a complete PPPoE header to the buffer pointed to by PTR */ -#define PPPOE_ADD_HEADER(PTR, CODE, SESS, LEN) \ - *(PTR)++ = PPPOE_VERTYPE; \ - *(PTR)++ = (CODE); \ - PPPOE_ADD_16(PTR, SESS); \ - PPPOE_ADD_16(PTR, LEN) - -#define PPPOE_DISC_TIMEOUT 5 /* base for quick timeout calculation (seconds) */ -#define PPPOE_SLOW_RETRY 60 /* persistent retry interval (seconds) */ -#define PPPOE_DISC_MAXPADI 4 /* retry PADI four times (quickly) */ -#define PPPOE_DISC_MAXPADR 2 /* retry PADR twice */ - /* * Locks used to protect struct members and global data * I immutable after creation Index: sys/net/if_pppoe.h =================================================================== RCS file: /cvs/src/sys/net/if_pppoe.h,v retrieving revision 1.8 diff -u -p -u -r1.8 if_pppoe.h --- sys/net/if_pppoe.h 29 Jun 2022 09:08:07 -0000 1.8 +++ sys/net/if_pppoe.h 2 Feb 2024 10:30:16 -0000 @@ -64,6 +64,61 @@ struct pppoeconnectionstate { #define PPPOEGETSESSION _IOWR('i', 112, struct pppoeconnectionstate) +struct pppoehdr { + u_int8_t vertype; + u_int8_t code; + u_int16_t session; + u_int16_t plen; +} __packed; + +struct pppoetag { + u_int16_t tag; + u_int16_t len; +} __packed; + +#define PPPOE_HEADERLEN sizeof(struct pppoehdr) +#define PPPOE_OVERHEAD (PPPOE_HEADERLEN + 2) +#define PPPOE_VERTYPE 0x11 /* VER=1, TYPE = 1 */ + +#define PPPOE_TAG_EOL 0x0000 /* end of list */ +#define PPPOE_TAG_SNAME 0x0101 /* service name */ +#define PPPOE_TAG_ACNAME 0x0102 /* access concentrator name */ +#define PPPOE_TAG_HUNIQUE 0x0103 /* host unique */ +#define PPPOE_TAG_ACCOOKIE 0x0104 /* AC cookie */ +#define PPPOE_TAG_VENDOR 0x0105 /* vendor specific */ +#define PPPOE_TAG_RELAYSID 0x0110 /* relay session id */ +#define PPPOE_TAG_MAX_PAYLOAD 0x0120 /* RFC 4638 max payload */ +#define PPPOE_TAG_SNAME_ERR 0x0201 /* service name error */ +#define PPPOE_TAG_ACSYS_ERR 0x0202 /* AC system error */ +#define PPPOE_TAG_GENERIC_ERR 0x0203 /* generic error */ + +#define PPPOE_CODE_PADI 0x09 /* Active Discovery Initiation */ +#define PPPOE_CODE_PADO 0x07 /* Active Discovery Offer */ +#define PPPOE_CODE_PADR 0x19 /* Active Discovery Request */ +#define PPPOE_CODE_PADS 0x65 /* Active Discovery Session confirmation */ +#define PPPOE_CODE_PADT 0xA7 /* Active Discovery Terminate */ + +/* two byte PPP protocol discriminator, then IP data */ +#define PPPOE_MTU (ETHERMTU - PPPOE_OVERHEAD) +#define PPPOE_MAXMTU PP_MAX_MRU + +/* Add a 16 bit unsigned value to a buffer pointed to by PTR */ +#define PPPOE_ADD_16(PTR, VAL) \ + *(PTR)++ = (VAL) / 256; \ + *(PTR)++ = (VAL) % 256 + +/* Add a complete PPPoE header to the buffer pointed to by PTR */ +#define PPPOE_ADD_HEADER(PTR, CODE, SESS, LEN) \ + *(PTR)++ = PPPOE_VERTYPE; \ + *(PTR)++ = (CODE); \ + PPPOE_ADD_16(PTR, SESS); \ + PPPOE_ADD_16(PTR, LEN) + +#define PPPOE_DISC_TIMEOUT 5 /* base for quick timeout calculation (seconds) */ +#define PPPOE_SLOW_RETRY 60 /* persistent retry interval (seconds) */ +#define PPPOE_DISC_MAXPADI 4 /* retry PADI four times (quickly) */ +#define PPPOE_DISC_MAXPADR 2 /* retry PADR twice */ + #ifdef _KERNEL extern struct mbuf_queue pppoediscinq;