{"id":15007478,"url":"https://github.com/landhb/drawbridge","last_synced_at":"2025-04-06T22:09:20.404Z","repository":{"id":39970354,"uuid":"122649277","full_name":"landhb/DrawBridge","owner":"landhb","description":"Layer 4 Single Packet Authentication Linux kernel module utilizing Netfilter hooks and kernel supported Berkeley Packet Filters (BPF)","archived":false,"fork":false,"pushed_at":"2023-10-14T22:58:51.000Z","size":1125,"stargazers_count":113,"open_issues_count":0,"forks_count":23,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-04-06T22:09:14.235Z","etag":null,"topics":["bpf","iptables","iptables-extension","knocker","linux-kernel","netfilter","port-knock","port-knocker","port-knocking","rust"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/landhb.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2018-02-23T17:03:19.000Z","updated_at":"2025-03-21T14:53:11.000Z","dependencies_parsed_at":"2023-10-15T20:10:29.762Z","dependency_job_id":null,"html_url":"https://github.com/landhb/DrawBridge","commit_stats":{"total_commits":173,"total_committers":8,"mean_commits":21.625,"dds":0.3063583815028902,"last_synced_commit":"128a5bbf32b41145f4cbe08161e67ed10b6992c2"},"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/landhb%2FDrawBridge","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/landhb%2FDrawBridge/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/landhb%2FDrawBridge/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/landhb%2FDrawBridge/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/landhb","download_url":"https://codeload.github.com/landhb/DrawBridge/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247557767,"owners_count":20958047,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bpf","iptables","iptables-extension","knocker","linux-kernel","netfilter","port-knock","port-knocker","port-knocking","rust"],"created_at":"2024-09-24T19:10:15.125Z","updated_at":"2025-04-06T22:09:20.387Z","avatar_url":"https://github.com/landhb.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"![logo](https://github.com/landhb/DrawBridge/blob/master/img/logo.PNG?raw=true)\n\n[![Actions Status](https://github.com/landhb/Drawbridge/workflows/Ubuntu%20Latest%20Build%20CI/badge.svg)](https://github.com/landhb/Drawbridge/actions)\n\nA layer 4 Single Packet Authentication (SPA) Module, used to conceal TCP/UDP ports on public facing machines and add an extra layer of security. \n\nNote: DrawBridge now supports both IPv4 and IPv6 traffic\n\n## Demo\n\n![gif](https://github.com/landhb/DrawBridge/blob/master/img/example.gif?raw=true)\n\nPlease read the corresponding [article](https://www.landhb.me/posts/bODdK/port-knocking-with-netfilter-kernel-modules/) for a more in-depth look at the design. \n\n## Basic usage\n\n```bash\nsudo db auth --server [REMOTE_SERVER] --dport 53 -p udp --unlock [PORT_TO_UNLOCK]\n```\n\nTo give the `db` binary CAP_NET_RAW privs so that you don't need `sudo` to run it:\n\n```bash\nchmod 500 ~/.cargo/bin/db\nsudo setcap cap_net_raw=pe ~/.cargo/bin/db\n```\n\nIt's also convenient to create a bash alias to run `db` automatically when you want to access the port that it's guarding.\n\n```bash\nalias \"connect\"=\"db auth -s [REMOTE] -d 53 -p udp --unlock [PORT] \u0026\u0026 ssh -p [PORT] user@[REMOTE]\"\n```\n\n## CI/CD \u0026 Supported Kernel Versions\n\n| Kernel Version | Build   | Insmod  | Tests   |\n| :---:    |  :---:     |  :---:     |  :---:     |\n| 6.0.6   |  ![Build](https://raw.githubusercontent.com/landhb/DrawBridge/badges/master/build-6.0.6-badge.svg)  | ![Insmod](https://raw.githubusercontent.com/landhb/DrawBridge/badges/master/insmod-6.0.6-badge.svg)  | ![Test](https://raw.githubusercontent.com/landhb/DrawBridge/badges/master/test-6.0.6-badge.svg)  |\n| 5.17.2   |  ![Build](https://raw.githubusercontent.com/landhb/DrawBridge/badges/master/build-5.17-badge.svg)  | ![Insmod](https://raw.githubusercontent.com/landhb/DrawBridge/badges/master/insmod-5.17-badge.svg)  | ![Test](https://raw.githubusercontent.com/landhb/DrawBridge/badges/master/test-5.17-badge.svg)  |\n| 5.15.33  |  ![Build](https://raw.githubusercontent.com/landhb/DrawBridge/badges/master/build-5.15-badge.svg)  | ![Insmod](https://raw.githubusercontent.com/landhb/DrawBridge/badges/master/insmod-5.15-badge.svg)  | ![Test](https://raw.githubusercontent.com/landhb/DrawBridge/badges/master/test-5.15-badge.svg)  |\n| 5.10.110 |  ![Build](https://raw.githubusercontent.com/landhb/DrawBridge/badges/master/build-5.10-badge.svg)  | ![Insmod](https://raw.githubusercontent.com/landhb/DrawBridge/badges/master/insmod-5.10-badge.svg)  | ![Test](https://raw.githubusercontent.com/landhb/DrawBridge/badges/master/test-5.10-badge.svg)  |\n| 5.8.9    |  ![Build](https://raw.githubusercontent.com/landhb/DrawBridge/badges/master/build-5.8-badge.svg)  | ![Insmod](https://raw.githubusercontent.com/landhb/DrawBridge/badges/master/insmod-5.8-badge.svg)  | ![Test](https://raw.githubusercontent.com/landhb/DrawBridge/badges/master/test-5.8-badge.svg)  |\n| 5.4.188  |  ![Build](https://raw.githubusercontent.com/landhb/DrawBridge/badges/master/build-5.4-badge.svg)  | ![Insmod](https://raw.githubusercontent.com/landhb/DrawBridge/badges/master/insmod-5.4-badge.svg)  | ![Test](https://raw.githubusercontent.com/landhb/DrawBridge/badges/master/test-5.4-badge.svg)  |\n| 4.19.237 |  ![Build](https://raw.githubusercontent.com/landhb/DrawBridge/badges/master/build-4.19-badge.svg)  | ![Insmod](https://raw.githubusercontent.com/landhb/DrawBridge/badges/master/insmod-4.19-badge.svg)  | ![Test](https://raw.githubusercontent.com/landhb/DrawBridge/badges/master/test-4.19-badge.svg)  |\n| 4.14.275 |  ![Build](https://raw.githubusercontent.com/landhb/DrawBridge/badges/master/build-4.14-badge.svg)  | ![Insmod](https://raw.githubusercontent.com/landhb/DrawBridge/badges/master/insmod-4.14-badge.svg)  | ![Test](https://raw.githubusercontent.com/landhb/DrawBridge/badges/master/test-4.14-badge.svg)  |\n| 4.9.309  |  ![Build](https://raw.githubusercontent.com/landhb/DrawBridge/badges/master/build-4.9-badge.svg)  | ![Insmod](https://raw.githubusercontent.com/landhb/DrawBridge/badges/master/insmod-4.9-badge.svg)  | ![Test](https://raw.githubusercontent.com/landhb/DrawBridge/badges/master/test-4.9-badge.svg)  |\n| 4.4.302  |  ![Build](https://raw.githubusercontent.com/landhb/DrawBridge/badges/master/build-4.4-badge.svg)  | ![Insmod](https://raw.githubusercontent.com/landhb/DrawBridge/badges/master/insmod-4.4-badge.svg)  | ![Test](https://raw.githubusercontent.com/landhb/DrawBridge/badges/master/test-4.4-badge.svg)  |\n\n\n## Build and Install the Drawbridge Utilities\n\nThe usermode tools are now written in Rust! Build and install them with cargo:\n\n```\ngit clone https://github.com/landhb/Drawbridge\ncargo install --path Drawbridge/tools\n\n# or \ncargo install dbtools\n```\n\n## Build and Install the Drawbridge Module\n\nTo automagically generate keys, run the following on your client machine:\n\n```bash\ndb keygen\n```\n\nThe output of the keygen utility will be three files: `~/.drawbridge/db_rsa`, `~/.drawbridge/db_rsa.pub` and `key.h`. Keep `db_rsa` safe, it's your private key. `key.h` is the public key formated as a C-header file. It will be compiled into the kernel module.  \n\n\nTo compile the kernel module simply, bring `key.h`, cd into the kernel module directory and run `make`.\n\n```bash\n# on the server compile the module and load it\n# pass the ports you want to monitor as an argument\nmv key.h module/include/\ncd module/\nmake\nsudo modprobe x_tables\nsudo insmod drawbridge.ko ports=22,445 \n```\n\nYou may need to install your kernel headers to compile the module, you can do so with:\n\n```\nsudo apt-get install linux-headers-$(uname -r)\nsudo apt-get update \u0026\u0026 sudo apt-get upgrade\n```\n\nThis code has been tested on Linux Kernels between 4.X and 5.9. I don't plan to support anything earlier than 4.X but let me know if you encounter some portabilitity issues on newer kernels. \n\n## Customizing a Unique 'knock' Packet \n\nIf you wish to customize your knock a little more you can edit the TCP header options in client/bridge.c. For instance, maybe you want to make your knock packet have the PSH,RST,and ACK flags set and a window size of 3104. Turn those on:\n\n```c\n// Flags\n(*pkt)-\u003etcp_h.fin = 0;   // 1\n(*pkt)-\u003etcp_h.syn = 0;   // 2\n(*pkt)-\u003etcp_h.rst = 1;   // 4\n(*pkt)-\u003etcp_h.psh = 1;   // 8\n(*pkt)-\u003etcp_h.ack = 1;   // 16\n(*pkt)-\u003etcp_h.urg = 0;   // 32\n\n\n(*pkt)-\u003etcp_h.window = htons(3104);\n```\n\nThen make sure you can create a BPF filter to match that specific packet. For the above we would have RST(4) + PSH(8) + ACK(16) = 28 and the offset for the window field in the TCP header is 14:\n\n```\n\"tcp[tcpflags] == 28 and tcp[14:2] = 3104\"\n```\n\n[Here is a good short article on tcp flags if you're unfamiliar.](https://danielmiessler.com/study/tcpflags/). Because tcpdump doesn't support tcp offset shortcuts for IPv6 you have to work with offsets relative to the IPv6 header to support it:\n\n```\n(tcp[tcpflags] == 28 and tcp[14:2] = 3104) or (ip6[40+13] == 28 and ip6[(40+14):2] = 3104)\"\n```\n\nAfter you have a working BPF filter, you need to compile it and include the filter in the kernel module server-side. So to compile this and place the output in kernel/listen.c in struct sock_filter code[]:\n\n```\ntcpdump \"(tcp[tcpflags] == 28 and tcp[14:2] = 3104) or (ip6[40+13] == 28 and ip6[(40+14):2] = 3104)\" -dd\n```\n\nwhich gives us:\n\n```c\nstruct sock_filter code[] = {\n\t{ 0x28, 0, 0, 0x0000000c },\n\t{ 0x15, 0, 9, 0x00000800 },\n\t{ 0x30, 0, 0, 0x00000017 },\n\t{ 0x15, 0, 13, 0x00000006 },\n\t{ 0x28, 0, 0, 0x00000014 },\n\t{ 0x45, 11, 0, 0x00001fff },\n\t{ 0xb1, 0, 0, 0x0000000e },\n\t{ 0x50, 0, 0, 0x0000001b },\n\t{ 0x15, 0, 8, 0x0000001c },\n\t{ 0x48, 0, 0, 0x0000001c },\n\t{ 0x15, 5, 6, 0x00000c20 },\n\t{ 0x15, 0, 5, 0x000086dd },\n\t{ 0x30, 0, 0, 0x00000043 },\n\t{ 0x15, 0, 3, 0x0000001c },\n\t{ 0x28, 0, 0, 0x00000044 },\n\t{ 0x15, 0, 1, 0x00000c20 },\n\t{ 0x6, 0, 0, 0x00040000 },\n\t{ 0x6, 0, 0, 0x00000000 },\n};\n```\n\nAnd there you go! You have a unique packet that the DrawBridge kernel module will parse!\n\n\n## Generating an RSA Key Pair Manually\n\nFirst generate the key pair:\n\n```\nopenssl genrsa -des3 -out private.pem 2048\n```\n\nExport the public key to a seperate file:\n\n```bash\nopenssl rsa -in private.pem -outform DER -pubout -out public.der\n```\n\nIf you take a look at the format, you'll see that this doesn't exactly match the kernel struct representation of a public key, so we'll need to extract the relevant data from the BIT_STRING field in the DER format:\n\n```bash\nvagrant@ubuntu-xenial:~$ openssl asn1parse  -in public.der -inform DER\n\n0:d=0  hl=4 l= 290 cons: SEQUENCE\n4:d=1  hl=2 l=  13 cons: SEQUENCE\n6:d=2  hl=2 l=   9 prim: OBJECT            :rsaEncryption\n17:d=2  hl=2 l=   0 prim: NULL\n19:d=1  hl=4 l= 271 prim: BIT STRING        \u003c-------------------- THIS IS WHAT WE NEED\n```\n\nYou can see that the BIT_STRING is at offset 19. From here we can extract the relevant portion of the private key format to provide the kernel module:\n\n```bash\nopenssl asn1parse  -in public.der -inform DER -strparse 19 -out output.der\n```\n\nYou'll notice that this is compatible with [RFC 3447 where it outlines ASN.1 syntax for an RSA public key](https://tools.ietf.org/html/rfc3447#page-44).\n\n```bash\n0:d=0  hl=4 l= 266 cons: SEQUENCE\n4:d=1  hl=4 l= 257 prim: INTEGER           :BB82865B85ED420CF36054....\n265:d=1  hl=2 l=   3 prim: INTEGER           :010001\n```\n\nIf you need to dump output.der as a C-style byte string:\n\n```bash\nhexdump -v -e '16/1 \"_x%02X\" \"\\n\"' output.der | sed 's/_/\\\\/g; s/\\\\x  //g; s/.*/    \"\u0026\"/'\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flandhb%2Fdrawbridge","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flandhb%2Fdrawbridge","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flandhb%2Fdrawbridge/lists"}