jvinet / knock

A port-knocking daemon
http://www.zeroflux.org/projects/knock
GNU General Public License v2.0
549 stars 113 forks source link

IPv6 is not supported under this link-layer type #83

Open BitBlit88 opened 2 years ago

BitBlit88 commented 2 years ago

Hello,

I tried to add IPv6 support to my knockd service using knockd version 0.8.

Here is my /etc/knockd.conf: [options] UseSyslog Interface = venet0

[SSH] sequence = 1234,5678,9012 seq_timeout = 5 start_command = ufw allow from %IP% to any port 22 proto tcp tcpflags = syn cmd_timeout = 10 stop_command = ufw delete allow from %IP% to any port 2 proto tcp

and ifconfig: lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 inet6 ::1 prefixlen 128 scopeid 0x10 loop txqueuelen 1000 (Local Loopback) RX packets 632682 bytes 121494481 (121.4 MB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 632682 bytes 121494481 (121.4 MB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

venet0: flags=211<UP,BROADCAST,POINTOPOINT,RUNNING,NOARP> mtu 1500 inet 127.0.0.1 netmask 255.255.255.255 broadcast 0.0.0.0 destination 127.0.0.1 inet6 2a01:xxx:xxx:xxx:xxx:xxx:xxx:xxx prefixlen 128 scopeid 0x0 unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 txqueuelen 0 (UNSPEC) RX packets 80663 bytes 6564767 (6.5 MB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 37029 bytes 15021778 (15.0 MB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

venet0:0: flags=211<UP,BROADCAST,POINTOPOINT,RUNNING,NOARP> mtu 1500 inet 81.yyy.yyy.yyy netmask 255.255.255.255 broadcast 81.yyy.yyy.yyy destination 81.yyy.yyy.yyy unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 txqueuelen 0 (UNSPEC)

If I try to knock via IPv6 I get the following message in syslog: knockd[23619]: IPv6 is not supported under this link-layer type

Ipv4 doesn't work neither with this configuration.

If I change the config to

[options] UseSyslog Interface = venet0:0

Ipv4 works but Ipv6 doesn't because venet0:0 is only bound to an IPv4 address.

How could I get IPv4 and IPv6 get working?

TDFKAOlli commented 2 years ago

Hi @BitBlit88 ,

the problem output comes from here: https://github.com/jvinet/knock/blob/cb163f1509f57698c40a1bd8d1d6891af608a18b/src/knockd.c#L1683

That means that the sniffer detected an IPv6 IP packet and now tries to handle it. But there is an issue with setting 'ip6' which is checked in the very next line. https://github.com/jvinet/knock/blob/cb163f1509f57698c40a1bd8d1d6891af608a18b/src/knockd.c#L1684

Here it is set: https://github.com/jvinet/knock/blob/cb163f1509f57698c40a1bd8d1d6891af608a18b/src/knockd.c#L1643 So that the case of 'if(lltype == DLT_EN10MB)'. Anyhow there are two other cases where 'ip6' is not properly set in the 'elseif' cases here: https://github.com/jvinet/knock/blob/cb163f1509f57698c40a1bd8d1d6891af608a18b/src/knockd.c#L1646 and here: https://github.com/jvinet/knock/blob/cb163f1509f57698c40a1bd8d1d6891af608a18b/src/knockd.c#L1649

I guess you now have one of the ifelse-cases and thereby ip6 pointer is not properly set and knockd bails out with the error logile you have seen.

I fixed it in my fork here: https://github.com/TDFKAOlli/knock/blob/58a2ed4585af7c7bd9b19bfd82e3f2fa522c0a42/src/knockd.c#L1662 and here: https://github.com/TDFKAOlli/knock/blob/58a2ed4585af7c7bd9b19bfd82e3f2fa522c0a42/src/knockd.c#L1666 but I couldn't test it, cause I never run into those lines. Anyhow you can try to patch your version and test or create a pull request for this repository.

BitBlit88 commented 2 years ago

Hi @TDFKAOlli,

your fix works very well. But I have still the problem that either IPv4 or IPv6 works but not both together. Unfortunately my provider forces to set IPv6 on interface "venet0:0" and IPv4 on interface "venet0". I think knockd can't listen on two interfaces. The only solution I see is running two instances of knockd listening on different interfaces or some kind of network bonding.

TDFKAOlli commented 2 years ago

@BitBlit88 , good to head it is working 😄 Can you create a pull request? I guess it can help others too. And yes, multiple interface support is not yet there. I thought in the past about trying to add it, but in the end it seems I didn't needed it enough to start working on it 😉 . But I guess your proposal of running two knockd processes would work.

TDFKAOlli commented 2 years ago

Hey @BitBlit88 , I just read this about pcap:

pcap_open_live() is used to obtain a packet capture handle to look at packets on the network. device is a string that specifies the network device to open; on Linux systems with 2.2 or later kernels, a device argument of "any" or NULL can be used to capture packets from all interfaces.

Written here: https://www.tcpdump.org/manpages/pcap_open_live.3pcap.html

So it might work that you simply use "any" as interface in the knockd config. (Or you add a config to use any in pcap_open_live()). The drawback is, it really listens then to any interface, not only the the two interfaces you want it to listen too. But that might be o.k.

EDIT: Ah, no, one more change is needed, here: https://github.com/jvinet/knock/blob/cb163f1509f57698c40a1bd8d1d6891af608a18b/src/knockd.c#L280 This is fetching the IP-address of the interface, but checks for the interface name. I guess it should be changed so it matched either the interface name or "any" and in both cases fetches the IP-address.

BitBlit88 commented 2 years ago

Hi @TDFKAOlli,

you are great! Thanks for pointing this out.

I change the line to if((strcmp(ifa->ifa_name, o_int) == 0 || strcmp("any", o_int) == 0) && (ifa->ifa_addr->sa_family == AF_INET || (ifa->ifa_addr->sa_family == AF_INET6 && !o_skipIpV6))) {

and modified "knockd.conf" to Interface = any

Now both IPv4 and Ipv6 works. I will cherry pick your changes with the above code and make a pull request.

TDFKAOlli commented 2 years ago

No prob, came to my mind just now. Before I thought about parsing a list of interfaces and then spawning several knockds for it so to handle each interface by an own thread... This "any" is much more simpler and would do in most cases I guess. 😄