haakonnessjoen / MAC-Telnet

Open source MAC Telnet client and server for connecting to Mikrotik RouterOS routers and Posix devices using MAC addresses
http://lunatic.no/2010/10/routeros-mac-telnet-application-for-linux-users/
GNU General Public License v2.0
396 stars 127 forks source link

Making mactelnet client to connect from RockyLinux8 (RHEL8, Centos8) to a mikrotik #92

Closed axodd closed 2 months ago

axodd commented 3 months ago

Here is my complete "walkthrough" with an odd outcome: walkthrough.txt

haakonnessjoen commented 3 months ago

You could try with the -n parameter, and see if you have more luck. Another way to debug would be to run wireshark, or tcpdump -i yourlaninterface -w file.pcap and check for the mactelnet packets. I have added a mactelnet dissector to wireshark, so it should show you a detailed view of the packets, and what they do.

For the auto discovery look for the mdns packets in wireshark.

axodd commented 3 months ago

Thanks a lot for your great ideas!

Alas, "-n" (do not use broadcast packets) did not make a difference, and I've also tried on another RouterOS/mikrotik model (RouterOS v6.49.15 off-the-shelf factory defaults; wanna try ROS v7 next). While tcpdumping attempts, all i'm seeing are STP broadcasts like: STP 802.1w, Rapid STP, Flags [Learn, Forward], bridge-id 8000.d4:...:b7.8003, length 43 where bridge-id is the "Admin. MAC Address" of the LAN bridge i was trying to reach. However, these are generated even w/o running mactelnet (also seen with "tcpdump -i ens10u3 ether broadcast or ether multicast") and I didn't see any special autodiscovery multicast DNS packets while running "mndp". Same when running mactelnet against MAC address of specific NIC port i was connected to.

Was anyone able to use the program on any RHEL8-based OS (like Centos8, RockyLinux8, AlmaLinux8) so far? I wonder if this is because autoconf is v2.69 in RHEL8 and if so, should I try and compile the program using makefile bypassing autogen entirely like suggested in https://github.com/haakonnessjoen/MAC-Telnet/issues/80#issuecomment-1457921574

While the binary builds and seems to run as normal (no errors in stdout, and it even prompts for user and password), it seems to be actually doing nothing. It just keeps "Searching for MikroTik routers..." and then "Connecting to.." MAC forever. There are some warnings and errors in the config.log (attached below) such as:

configure:7905: gcc -c -g -O2  conftest.c >&5
conftest.c: In function 'main':
conftest.c:85:20: error: expected expression before ')' token
 if (sizeof ((pid_t)))
                    ^
configure:7905: $? = 1
configure: failed program was:
| /* confdefs.h */
| #define PACKAGE_NAME "mactelnet"

...

configure:7916: gcc -c -g -O2  conftest.c >&5
conftest.c: In function 'main':
conftest.c:85:21: error: expected expression before ')' token
 if (sizeof ((size_t)))
                     ^
configure:7916: $? = 1
configure: failed program was:
| /* confdefs.h */
| #define PACKAGE_NAME "mactelnet"

...

configure:8026: result: no
configure:8026: checking vfork.h presence
configure:8026: gcc -E  conftest.c
conftest.c:51:10: fatal error: vfork.h: No such file or directory
 #include <vfork.h>
          ^~~~~~~~~
compilation terminated.
configure: failed program was:
| /* confdefs.h */
| #define PACKAGE_NAME "mactelnet"

... 

configure:8364: gcc -o conftest -g -O2   conftest.c -lrt  >&5
/tmp/ccFLITRG.o: In function 'main':
/home/alxc/Downloads/MAC-Telnet/conftest.c:92: undefined reference to 'arc4random'
collect2: error: ld returned 1 exit status
configure:8364: $? = 1
configure: failed program was:
| /* confdefs.h */
| #define PACKAGE_NAME "mactelnet"

(all such warnings and errors are in the grep.config.log attached)

haakonnessjoen commented 3 months ago

Could you upload a packet capture from the network interface that has the mikrotik connected to it, while you are trying to connect to it with mactelnet?

axodd commented 3 months ago

Please find both mactelnet and mndp captures attached (github doesn't support pcap blobs as attachments, so i've read them with tcpdump -r and saved as plain text). In an earlier attempt when i had access to another device (hex model vs. my current hex lite), i did spot one multicast among usual STPs on tcpdump's stdout that looked as follows:

16:34:45.795429 IP 192.168.88.88.mdns > mdns.mcast.net.mdns: 0 [7q] PTR (QM)? _nfs._tcp.local. PTR (QM)? _ftp._tcp.local. PTR (QM)? _webdav._tcp.local. PTR (Q
M)? _webdavs._tcp.local. PTR (QM)? _sftp-ssh._tcp.local. PTR (QM)? _smb._tcp.local. PTR (QM)? _afpovertcp._tcp.local. (118)

but still couldn't access device (pwd prompt, then "Connection failed" a few seconds later). In case it matters, both mikrotiks are not yet upgraded to RouterOS v7 (i.e. still on v6) but I plan on upgrading them to v7 when I get a chance. mactelnet3.log mndp3.log

haakonnessjoen commented 2 months ago

which version of 6? If it is a very old one, try with the -o flag (before the mac address)

But your dump seems to say that it doesn't try to send on that interface at all. Do you have an ip on that interface?

axodd commented 2 months ago

Yes, of course, I can ping and SSH over tcp/ip just fine (as well as use http ui interface of the tik); it's only mactelnet and macping that are timing out. Mikrotiks firmware versions are v6.49.15 and v6.48.7 (as mentioned above), so shouldn't require fallback to MD5 (pre 6.43). MAC telnet server is On on the tiks, and can be accessed via mikrotik's Winbox application alright also.

I will try and upgrade these tiks to the latest v7 version later this week; however, the latest RHEL8.8 (RockyLinux) uses Autoconf 2.69 by default (i.e. less than your minimal requirement of Autoconf 2.71), so I suspect that my compilation may have produced the binaries that appear to work but are missing essential functions. Here are their sizes:

mactelnet : 183648 bytes
macping :  85384 bytes
mndp : 55800 bytes
haakonnessjoen commented 2 months ago

I don' think you should be able to compile anything without essential functions.

You could also try to run mactelnet with sudo and -n which uses a completely different way to send packets.

Maybe you could send me the the actual pcap files of attempts with and without -n, prefferrably where you use mactelnet with your mikrotik's mac-address as the destination argument, not the identity for these tests. And also the output of ip addr sh and/or ifconfig in a mail to haakon.nessjoen+gh@gmail.com I could see if I can see anything else that could be an issue.

axodd commented 2 months ago

Thanks for pointing me in the right direction. Finally got around to writing this up.

Upgraded one tik (hex) from current v6 (supported long-term release) to stable v7.12.1 (new features go to v7), while leaving another tik on v6, but there were no changes in symptoms (with and without "-n"): same "Connection failed" despite accessing via IP address working fine. Also, both v6 and v7 ROS devices communicated w/each other via their own Mac Telnet client (/tool/mac-telnet) without problems. In tcpdumps there was no traffic but usual STPs from the tik, so I took time to dig deeper and found the root cause. Two things contributed together:

  1. My usage of tcpdump - i didn't take enough time to wait for the tcpdump to process all packets in buffer after mactelnet exits, but stopped tcpdump almost immediately after each mactelnet test. Waiting a few extra seconds before Ctrl+C'ing tcpdump would allow to see the mactelnet's UDP packet capture. That's why i only saw the irrelevant STPs in my previous tests! Also, with tcpdump I should've used better flags to see more information, such as: tcpdump -nne -i ens12u2|grep -v STP or tcpdump -nne -vv -i ens12u2|grep -v STP This has helped understand and solve the second (primary) half of the problem below.

  2. Firewall - turns out, LAN interface is under the same "public" firewalld zone as WAN interface by default (all interfaces by default are added to the default firewalld zone and the "public" zone is default), so the incoming reply packets from the tik's source port 20561/udp were filtered out by default.

In Centos8 / RL8 / RHEL8 (and many other recent Linux-based flavors), good old iptables firewall is superceded with nftables-under-firewalld-wrapper-frontend-with-network-manager-over-dbus kind of "concoction", which is more tricky to use compared to just iptables with plain ifcfg interface files. One can use nft list ruleset command to see current state/rules of the underlying kernel firewall. Gotta learn nftables, but to only allow one port on LAN interface I created internal.xml firewalld zone, and one could also use trusted.xml if she trusted all traffic on LAN:

$ cat /etc/firewalld/zones/internal.xml
<?xml version="1.0" encoding="utf-8"?>
<zone>
  <short>Internal</short>
  <description>For use on internal networks.</description>
  <source-port port="20561" protocol="udp"/>
</zone>

$ cat /etc/firewalld/zones/trusted.xml
<?xml version="1.0" encoding="utf-8"?>
<zone target="ACCEPT">
  <short>Trusted</short>
  <description>All network connections are accepted.</description>
</zone>

Followed by:

$ firewall-cmd --permanent --zone=internal --change-interface=ens12u2
# or, if you also need mndp discovery to work:   
$ firewall-cmd --permanent --zone=trusted --change-interface=ens12u2

Alternatively, and especially if your interface is managed outside of NetworkManager, edit/add 'ZONE=internal' in your /etc/sysconfig/network-scripts/ifcfg-* file, if it exists for that LAN interface, to bind the new zone to that LAN interface. In a pinch, one could even install and use a gui wrapper program for desktop/laptop called "firewall-config" to add all the above.

As you mention on https://wiki.wireshark.org/Protocols/mactelnet page, Mactelnet uses UDP as its transport protocol and the UDP port for normal mactelnet traffic is 20561. As explained further on https://omniflux.com/devel/mikrotik/Mikrotik_MAC_Telnet_Procotol.txt page, the MAC Telnet protocol goes beyond just link layer (MAC addresses and arp requests) and operates at the transport layer (UDP broadcast). In case of a tik to tik connection, Mikrotik's own client /tool/mac-telnet uses ports 20561/udp <--> 20561/udp while the Open Source mactelnet client for Linux/MacOS uses the pair of 1561/udp (computer) <--> 20561/udp (mikrotik).

Since UDP is a connectionless protocol, once the mactelnet session is established, it appears to use an additional 1661/udp port on the local side to broadcast to the same mikrotik's 20561/udp and back. So all it needs is a single firewall rule to allow incoming connections back from the source port 20561/udp (port of origin at the mikrotik) over the LAN interface to finally see the MAC-Telnet protocol negotiation: mactelnet.png

This also fixes macping which uses 0.0.0.0.20561 > 255.255.255.255.20561 broadcast between NICs.

That port information would be good to have on the mactelnet's README.

Ironically, whitelisting that port alone was not enough the MNDP (Mikrotik Neighbor Discovery Protocol) discovery. In my case, it needed all traffic on LAN to be trusted for the mndp discovery to work (finds the tik within 15 seconds, yay!), otherwise both "mndp" and "mactelnet -l" just kept "Searching for MikroTik routers.." forever. Only when LAN is fully trusted, it works: the laptop's LAN socket 192.168.88.88:5353/udp multicast to 224.0.0.251:5353/udp via MDNS (multicast DNS) protocol. Whitelisting this mdns port (5353/udp) wasn't enough, something else seems to be involved at a lower layer during discovery: mndp.png

Interestingly, we can also see that Mikrotiks routinely do their own auto-discovery in the background, polling LAN every minute. First, from a high-numbered port such as 47852/udp they broadcast the initial MNDP packet to dst 255.255.255.255:5678/udp. Then, the Mikrotik's NIC (at a lower link level L2) follows this up by emitting a CDP (cisco discovery protocol) packet as well, trying to find both Cisco and Mikrotik routers on the network. This is repeated every 1 minute (with all the usual STPs in between, emitted from Routerboard every 2 seconds) by design.

So finally now everything (mactelnet, macping, mndp) works for me on RockyLinux8 (RHEL8/centos8/almalinux8) as expected!

By the way, you were right: my older autoconf version 2.69 < 2.71 (centos7, centos8, rhel8, rockylinux8, etc) wasn't at fault, although I did have to replace AC_PREREQ([2.71]) with AC_PREREQ([2.69]) manually in configure.ac to be able to compile the program in the first place. Hope to try it on Mac OSX based client at some point to see what autoconf version the apples are using. Maybe some day there will be a mactelnet package in the repo for easier installation via yum/dnf and brew (just like .deb on Ubuntu/Debian that can already be installed via apt, huge thanks for that!).

p.s. Piece of advice to anoyone who might still struggle with mactelnet after whitelisting 20561/udp in the firewall, or even after trusting all traffic on LAN interface connected to a mikrotik:

Thank you and everyone else who has contributed to building this amazing Free and Open Source Software!

haakonnessjoen commented 2 months ago

Great to hear that you figured it out! Not sure why I didn't ask you to check your firewall, it should have been one of my first thoughts. It normally is. hehe.