dhclient new commit are good but....

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

dhclient new commit are good but....

Sven F.
Dear readers,

  since 5.8 i ve been carrying around patches to manage :
* crazy server sending hostname like "crazy ISP name with space" ( in
one case the ignore or supersede failed to workaround the problem ),
it  is a bit hard to test, and it looks like some improvement was made
to crash fatal on all invalid network information,
* and a bridging case, which is more realistic :

Assuming the EGRESS is Bridged to a vether, a pair or something to
serve the same LAN to a VM or something else, the first dhclient will eat
the paquet in the BPF filter because MAC are ignored.

MAC are ignored for some obscure historic case where the dhcp server responded
with broadcast or something.

To see the problem , assuming em0 is egress like :

# ifconfig  em0
em0: flags=808b43<UP,BROADCAST,RUNNING,PROMISC,ALLMULTI,SIMPLEX,MULTICAST,AUTOCONF4>
mtu 1500
        lladdr 00:ff:18:0b:4a:ee
        index 1 priority 0 llprio 3
        groups: egress
        media: Ethernet autoselect (100baseTX full-duplex,rxpause,txpause)
        status: active
        inet 172.16.1.4 netmask 0xffffff00 broadcast 172.16.1.255

Bridge it to something

ifconfig  vether0 create
ifconfig  vether0 rdomain 1
ifconfig  bridge0 create
ifconfig  bridge0 add em0
ifconfig  bridge0 add vether0
#safety net
echo <<< EOF >> /etc/dhclient
interface "vether1" {
    send host-name "bridged-sub-host-1";
    send dhcp-lease-time 3600;
    ignore domain-name-servers,routers;
    require subnet-mask,domain-name-servers;
}
#testing
ifconfig  bridge0 up
route -T 1 exec dhclient vether0

No lease ! because dhclient on em0 is actually filtering them at bpf level
A year ago the hw_addr was kept inside the daemon so i am not sure how
to apply my bpf filter.

To not break something the path add a -m option to dhclient that
enable mac bpf filter awareness,

In configure_bpf_sock, I added a  ` uint8_t *  ether_addr_octet` param
that is not null
and setup in case -m is passed to fill in a slightly different filter.

        /* Set up the bpf filter program structure. */
        p.bf_len = dhcp_bpf_mac_filter_len;
        p.bf_insns = dhcp_bpf_mac_filter;
        dhcp_bpf_mac_filter[8].k = LOCAL_PORT;
        memcpy(&bits16, ether_addr_octet, sizeof(bits16));
        dhcp_bpf_mac_filter[10].k = ntohs(bits16);
        memcpy(&bits, ether_addr_octet + 2, sizeof(bits));
        dhcp_bpf_mac_filter[12].k = ntohl(bits);

with the filter :

struct bpf_insn dhcp_bpf_mac_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, 8),

    /* 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, 6),

    /* 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, 8, 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, 0, 1),      /* patch */

    /* check bootp.hw.addr 2 bytes */
    BPF_STMT(BPF_LD + BPF_H + BPF_IND, 50),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0000, 0, 3),      /* patch */
    /* check bootp.hw.addr 4 bytes */
    BPF_STMT(BPF_LD + BPF_W + BPF_IND, 52),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x00000000, 0, 1),  /* patch */

    /* If we passed all the tests, ask for the whole packet. */
    BPF_STMT(BPF_RET+BPF_K, (unsigned int)-1),

    /* Otherwise, drop it. */
    BPF_STMT(BPF_RET+BPF_K, 0),
};

int dhcp_bpf_filter_len = sizeof(dhcp_bpf_filter) / sizeof(struct bpf_insn);
int dhcp_bpf_mac_filter_len = sizeof(dhcp_bpf_mac_filter) /
sizeof(struct bpf_insn);

I would gladly test an officially made diff because this is becoming
hard to maintain,
and there should be use cases out there.

The only workaround I know is to put egress in a vether behind the bridges,
certainly something that could break anyway.

Thanks for reading up to there !

--
--
---------------------------------------------------------------------------------------------------------------------
Knowing is not enough; we must apply. Willing is not enough; we must do

Reply | Threaded
Open this post in threaded view
|

Re: dhclient new commit are good but....

Sven F.
On Wed, Jun 3, 2020 at 2:13 PM sven falempin <[hidden email]>
wrote:

> Dear readers,
>
>   since 5.8 i ve been carrying around patches to manage :
> * crazy server sending hostname like "crazy ISP name with space" ( in
> one case the ignore or supersede failed to workaround the problem ),
> it  is a bit hard to test, and it looks like some improvement was made
> to crash fatal on all invalid network information,
> * and a bridging case, which is more realistic :
>
> Assuming the EGRESS is Bridged to a vether, a pair or something to
> serve the same LAN to a VM or something else, the first dhclient will eat
> the paquet in the BPF filter because MAC are ignored.
>
> MAC are ignored for some obscure historic case where the dhcp server
> responded
> with broadcast or something.
>
> To see the problem , assuming em0 is egress like :
>
> # ifconfig  em0
> em0:
> flags=808b43<UP,BROADCAST,RUNNING,PROMISC,ALLMULTI,SIMPLEX,MULTICAST,AUTOCONF4>
> mtu 1500
>         lladdr 00:ff:18:0b:4a:ee
>         index 1 priority 0 llprio 3
>         groups: egress
>         media: Ethernet autoselect (100baseTX full-duplex,rxpause,txpause)
>         status: active
>         inet 172.16.1.4 netmask 0xffffff00 broadcast 172.16.1.255
>
> Bridge it to something
>
> ifconfig  vether0 create
> ifconfig  vether0 rdomain 1
> ifconfig  bridge0 create
> ifconfig  bridge0 add em0
> ifconfig  bridge0 add vether0
> #safety net
> echo <<< EOF >> /etc/dhclient
> interface "vether1" {
>     send host-name "bridged-sub-host-1";
>     send dhcp-lease-time 3600;
>     ignore domain-name-servers,routers;
>     require subnet-mask,domain-name-servers;
> }
> #testing
> ifconfig  bridge0 up
> route -T 1 exec dhclient vether0
>
> No lease ! because dhclient on em0 is actually filtering them at bpf level
> A year ago the hw_addr was kept inside the daemon so i am not sure how
> to apply my bpf filter.
>
> To not break something the path add a -m option to dhclient that
> enable mac bpf filter awareness,
>
> In configure_bpf_sock, I added a  ` uint8_t *  ether_addr_octet` param
> that is not null
> and setup in case -m is passed to fill in a slightly different filter.
>
>         /* Set up the bpf filter program structure. */
>         p.bf_len = dhcp_bpf_mac_filter_len;
>         p.bf_insns = dhcp_bpf_mac_filter;
>         dhcp_bpf_mac_filter[8].k = LOCAL_PORT;
>         memcpy(&bits16, ether_addr_octet, sizeof(bits16));
>         dhcp_bpf_mac_filter[10].k = ntohs(bits16);
>         memcpy(&bits, ether_addr_octet + 2, sizeof(bits));
>         dhcp_bpf_mac_filter[12].k = ntohl(bits);
>
> with the filter :
>
> struct bpf_insn dhcp_bpf_mac_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, 8),
>
>     /* 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, 6),
>
>     /* 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, 8, 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, 0, 1),      /* patch */
>
>     /* check bootp.hw.addr 2 bytes */
>     BPF_STMT(BPF_LD + BPF_H + BPF_IND, 50),
>     BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0000, 0, 3),      /* patch */
>     /* check bootp.hw.addr 4 bytes */
>     BPF_STMT(BPF_LD + BPF_W + BPF_IND, 52),
>     BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x00000000, 0, 1),  /* patch */
>
>     /* If we passed all the tests, ask for the whole packet. */
>     BPF_STMT(BPF_RET+BPF_K, (unsigned int)-1),
>
>     /* Otherwise, drop it. */
>     BPF_STMT(BPF_RET+BPF_K, 0),
> };
>
> int dhcp_bpf_filter_len = sizeof(dhcp_bpf_filter) / sizeof(struct
> bpf_insn);
> int dhcp_bpf_mac_filter_len = sizeof(dhcp_bpf_mac_filter) /
> sizeof(struct bpf_insn);
>
> I would gladly test an officially made diff because this is becoming
> hard to maintain,
> and there should be use cases out there.
>
> The only workaround I know is to put egress in a vether behind the bridges,
> certainly something that could break anyway.
>
> Thanks for reading up to there !
>

Hello,

I am trying to run stock bsd so the problems and solutions encountered
profit everyone here.

Above is the last piece of software I NEED to run modified
because I have use cases where the dhcp client runs on a bridged interface.

The current DHCP client gobbles *all packets* even when not being the
target of it.

I hope a fix like that can go through at one point or another ( by default
or through an option )

Best

--
--
---------------------------------------------------------------------------------------------------------------------
Knowing is not enough; we must apply. Willing is not enough; we must do