PlushBeaver / xdp-syn-cookie

XDP tutorial project
MIT License
42 stars 12 forks source link

No client challenge? #1

Open s3rj1k opened 4 years ago

s3rj1k commented 4 years ago

https://github.com/PlushBeaver/xdp-syn-cookie/blob/master/xdp_filter.c#L320

PlushBeaver commented 4 years ago

Hello @s3rj1k! I intended to add real client validation and checking if client address is validated as the next step of this demo project, but unfortunately I recently had little time for it. I do have some working code though, so feel free to ask. Basically, you have to declare a BPF map of type BPF_TYPE_HASH and call bpf_map_lookup_elem() to check if a client is validated and bpf_map_update_elem() to mark an IP validated after an ACK with a correct SYN cookie.

s3rj1k commented 4 years ago

@PlushBeaver I am willing to test it out, please share :)

s3rj1k commented 4 years ago

https://github.com/Orange-OpenSource/oko/blob/master/examples/bpf/stateful-firewall.c

PlushBeaver commented 4 years ago

Code pushed to usermode-proto branch.

Create a local directory and mount BPF FS there (see xdp_control.cc):

mkdir maps
sudo mount -t bpf none maps

After getting the stand up and attaching the filter, you can watch statistics and mange validated client list:

$ sudo ./xdp_control watch
time 1580352190
  pass 5089231 packets 274818515 bytes
  back 1 packets 74 bytes
  drop 939557 packets 50736078 bytes
$ sudo ./xdp_control list
192.0.2.2
$ sudo ./xdp_control delete 192.0.2.2
$ # see xdp_control.cc for more commands
s3rj1k commented 4 years ago

@PlushBeaver I am having trouble compiling this code on Ubuntu 19.10 with 5.3.0-29-generic kernel.

libbpf is compiled from git HEAD.

/usr/bin/ld: xdp_control.cc:(.text+0x3a6): undefined reference to `bpf_map_get_next_key'
/usr/bin/ld: xdp_control.cc:(.text+0x41f): undefined reference to `bpf_map_update_elem'
/usr/bin/ld: xdp_control.cc:(.text+0x436): undefined reference to `bpf_map_delete_elem'
/usr/bin/ld: xdp_control.cc:(.text+0x458): undefined reference to `bpf_map_lookup_elem'
s3rj1k commented 4 years ago

Also loading xdp like this, compiled from master brunch:

ip -force link set dev eth0 xdp object xdp_filter.o

Drops all inbound connections, outbound connections work.

s3rj1k commented 4 years ago

@PlushBeaver There is also bpf helper for syncookie https://www.fclose.com/linux-kernels/3990408-bpf-add-helper-to-check-for-a-valid-syn-cookie

I am wondering, can this be reused?

PlushBeaver commented 4 years ago

@s3rj1k,

  1. It appears, these functions were a bit renamed in upstream: https://github.com/iovisor/bcc/blob/master/src/cc/libbpf.h#L4. I test my code in Arch Linux 5.4.12-arch1-1 with libbpf-git 5188b0c-1.

  2. Yes, this filter drops all inbound connections with an RST, even the ones that provide a valid SYN cookie. The next connection from the same client will pass the filter, because client's IP is in the table. This is done because kernel does not know about this connection, as the handshake was handled by XDP. One workaround is to send an out-of-sequence ACK instead of RST, which will make the client to repeat the handshake without closing the connection. Note that some real-world middleboxes may interfere with this scheme.

  3. Reused in which way? You cannot call it, because it requires a struct bpf_sock*, which you do not have in an RX filter. You may be able to borrow some code from there, but it is already present in my sample.

s3rj1k commented 4 years ago

@PlushBeaver

  1. Hmm.
  2. Couldn't get SSH to work.
  3. Not a C person, but this test if I understand it correctly, uses XDP for syncookie filtering: https://github.com/torvalds/linux/blob/master/tools/testing/selftests/bpf/progs/test_tcp_check_syncookie_kern.c
PlushBeaver commented 4 years ago
  1. I have sshd running on my host and verify as follows:

    $ make all
    $ mkdir maps
    $ sudo mount -t bpf none maps
    $ sudo ./stand up
    $ sudo ./stand attach
    <output omitted>
    $ sudo ./xdp_control install
    bpf_prog_load() = 0 <--- success, despite of the following
    libbpf: failed to pin map: File exists
    bpf_object__pin_maps() = -17
    $ sudo ./stand exec ssh 192.0.2.1
    ssh: connect to host 192.0.2.1 port 22: Connection reset by peer <--- RST by filter
    $ sudo ./stand exec ssh 192.0.2.1
    root@192.0.2.1's password:  <--- SSH connected
  2. I didn't not know this function existed. It seems you're correct and it can be used here. I haven't tried it myself yet, so cannot comment further.

bottiger1 commented 4 years ago

One workaround is to send an out-of-sequence ACK instead of RST, which will make the client to repeat the handshake without closing the connection. Note that some real-world middleboxes may interfere with this scheme.

Are there any websites that document this behavior?

Do I just send a packet with only the ACK and no SYN flag with a random acknowledgement number?

PlushBeaver commented 4 years ago

@bottiger1, please pardon me for this misguiding typo. I meant to write "send an out-of-sequence SYNACK instead, then wait for an RST". By placing cookie in SYN-ACK's acknum you can get it in RST thus verifying the client. Statefull firewalls may block such SYN-ACKs as bogus. This scheme is also known as safe reset.

bottiger1 commented 4 years ago

Will that make the client auto-reconnect? Why bother doing it that way if it will cause a RST anyway?

PlushBeaver commented 4 years ago

Will that make the client auto-reconnect?

Yes, that's the point. Refer to Figure 10 of RFC 793.

scaetano84 commented 1 year ago

Hi @PlushBeaver I have already been able to assemble everything perfectly, the only problem I have is that from the server I cannot download or browse. How could I solve it?