How to copy & forward inbound / outbound DHCP packets to another host? (SOLVED)

Hi there,

I am tinkering around DHCP protocol and it would greatly help me if I could copy DHCP in / out packets to another host for further processing.

I only found this, but apparently I am not that smart to interpret fast how to use the Calea, or if it even is a right tool for the job: Copy packets and send to destination - #4 by CateFul

In Mikrotik I tried:

/ip firewall mangle
add action=sniff-pc chain=prerouting dst-port=67 log=yes log-prefix=sniff protocol=udp sniff-target=192.168.1.247 sniff-target-port=1067 src-port=68

which sends the data, but this is not a DHCP packet anymore and i’d have to implement some serialization and decoding to get the packets back.

Any ideas how should I do this?

BTW: I was searching this also for linux and found this: https://wiki.nftables.org/wiki-nftables/index.php/Duplicating_packets and this works well, though its Linux, not Mikrotik.

Use the DHCP-relay function ? Not sure what you want to accomplish…what do you mean by “further processing”

Sorry, let me explain in more detail: DHCP packets are running smoothly on a RouterOS, this is pure DHCP server.

I want to process packets exchanged between the RouterOS and the clients, but I do not want to alter them, reading is sufficient for now. To achieve this I can:

  • run DHCP relay, send the packets to multiple servers (ROuterOS and my processing host) and make the topology more complex,

  • insert a forwarding Linux with Nftables which does what I need (duplicate packets), but this obviously is even more complex and error prone:

table ip dhcp_dup {
chain dhcp_duplicate {type filter hook prerouting priority -150;
# Duplicate inbound DHCP requests (client -> server)
udp sport 68 udp dport 67 dup to 192.168.1.247
# Duplicate DHCP traffic on standard ports
udp sport 67 dup to 192.168.1.247
udp dport 67 dup to 192.168.1.247
}
chain dhcp_duplicate_output {type filter hook output priority -150;
# Duplicate outbound DHCP replies (server -> client)
udp sport 67 udp dport 68 dup to 192.168.1.247 }
}

*And this NFT snipped was not tested thoroughly, i am not sure how it behaves for broadcasts.

  • or I can sniff the DHCP packets in the same broadcast domain, but I will be limited to only broadcsts DHCP packets from clients, I will not see server replies or unicast messages exchanged when the host already has IP.

This all takes me to the only valid solution where RouterOS is able to duplicate / mirror the DHCP packets and send them over to external host (for my own statistics and pleasure). It would be best if I could send these packages over certain interface, as I really don’t want to re-broadcast them back to same broadcast domain….

One more detail: changing the topology is not really possible, I am working with distant networks and thus I cannot introduce extra relays or linux boxes most of the time, easily.

Hi,

have you tried mirroring?

Still dont get what you try to do with a “processing host”, but why not this:

And stream to your “processing host”.

Thank you so much for replies!

@BartoszP this is a very good option if someone has physical access to the network. I don’t have it unfortunately, so this is dead end as RouterOS does not support, AFAIK, eg. ERSPAN.

@Guscht yes, this is more valid approach, but RouterOS sniffer encodes the traffic into TZSP. This is not widely used protocol and on my “consumer” side I would have to implement it. This is not impossible, but I am just causally looking for a simpler solution than another process (thread). And, this would be only for RouterOS, which is ~10% of the DHCP population I care about.

I will keep chasing this, and if hard pressed, will implement this TZSP, based on wiki and scarce resources in the internet (as it has no RFC or cant find valid specs……)

And by the way, the example here:

/ip firewall mangle
add action=sniff-pc chain=prerouting dst-port=67 log=yes log-prefix=sniff protocol=udp sniff-target=192.168.1.247 sniff-target-port=1067 src-port=68

already is using TZSP so no need to use sniffer, methinks.

Tcpdumping the inbound traffic would result in some packets which can be open in Wireshark but are not particualrly usable for my code :slight_smile:

Ok, I implemented this TZSP protocol in my software and it works fine, but…. I fail to write any rule which would ever catch ANY UDP packet produced by the Mikrotik DHCP server :confused:

Honestly, I think that I have hit some RouterOS deficency here or I am missing some tine detail :slight_smile:

I mean:

  • works: inbound packets are forwarded fine with the rule:
    chain=prerouting action=sniff-tzsp sniff-target=192.168.1.247 sniff-target-port=37008 protocol=udp src-port=68 dst-port=67

    (notice, earlier I made a mistake and had sniff-pc, it should have been sniff-tzsp)

  • does not work: any outbound packets generated by the DHCP server cannot be catched by any rule in RouterOS firewall.

/ip/firewall/mangle> print stats
Flags: D - DYNAMIC
Columns: CHAIN, ACTION, BYTES, PACKETS
# CHAIN ACTION BYTES PACKETS
;;; special dummy rule to show fasttrack counters
0 D prerouting passthrough 14 563 693 788 14 748 171
;;; special dummy rule to show fasttrack counters
1 D forward passthrough 14 563 693 788 14 748 171
;;; special dummy rule to show fasttrack counters
2 D postrouting passthrough 14 563 693 788 14 748 171
;;; Sniff DHCP requests to MT
3 prerouting sniff-tzsp 560 003 1 666
;;; Sniff DHCP requests from MT
4 output sniff-tzsp 0 0
;;; Sniff DHCP requests from MT
5 postrouting sniff-tzsp 0 0
;;; Sniff DHCP requests from MT
6 forward sniff-tzsp 0 0
;;; Sniff DHCP requests from MT
7 postrouting sniff-tzsp 0 0
[admin@RB5009] /ip/firewall/mangle> ..raw/print stats
Flags: X - DISABLED; D - DYNAMIC
Columns: CHAIN, ACTION, BYTES, PACKETS
# CHAIN ACTION BYTES PACKETS
;;; special dummy rule to show fasttrack counters
0 D prerouting passthrough 14 563 693 788 14 748 171
;;; Debug DHCP raw output
1 output log 0 0
;;; Debug ICMP raw output
2 X output log 23 612 314

/ip firewall mangle
add action=sniff-tzsp chain=prerouting comment="Sniff DHCP requests to MT" dst-port=67 log-prefix="Input-67: " protocol=udp sniff-target=192.168.1.247 sniff-target-port=37008 src-port=68
add action=sniff-tzsp chain=output comment="Sniff DHCP requests from MT" dst-port=68 log-prefix="Output-67: " protocol=udp sniff-target=192.168.1.247 sniff-target-port=37008 src-port=67
add action=sniff-tzsp chain=postrouting comment="Sniff DHCP requests from MT" dst-port=68 log-prefix="Postrouting-67: " protocol=udp sniff-target=192.168.1.247 sniff-target-port=37008 src-port=67
add action=sniff-tzsp chain=forward comment="Sniff DHCP requests from MT" dst-port=68 log-prefix="Forward-67: " protocol=udp sniff-target=192.168.1.247 sniff-target-port=37008 src-port=67
add action=sniff-tzsp chain=postrouting comment="Sniff DHCP requests from MT" dst-port=68 protocol=udp sniff-target=192.168.1.247 sniff-target-port=37008 src-port=67

/ip firewall raw
add action=log chain=output comment="Debug DHCP raw output" dst-port=67,68 log-prefix="RAW-output-67: " protocol=udp src-port=67,68
add action=log chain=output comment="Debug ICMP raw output" disabled=yes log-prefix="RAW-output-ICMP: " protocol=icmp

And Sniffer config also gives me hard time, won’t send data today :slight_smile:

Let’s call it a day, I think that this is worth a Mikrotik expert look or supout :slight_smile:

BTW: LLM made the TZSP implementation in under a minute.

You'd have to use chain=output rule to do TZSP on that side of the DHCP server.

IPv4 DHCP uses raw sockets, that's why you cannot catch or drop the packets on the output chain, because they are not visible to the firewall.

The DHCP processes also get the incoming IPv4 DHCP traffics before they arrive at the firewall, so dropping them to prevent the DHCP client/server from seeing them is also not possible. But at least the FW can see the inbound packets.

Thank you @Amm0 for looking at this!

I thought I had this done… mangle:

;;; Sniff DHCP requests from MT
chain=output action=sniff-tzsp sniff-target=192.168.1.247 sniff-target-port=37008 protocol=udp src-port=67,68 dst-port=67,68 log-prefix="Output-67: "

and

..raw/print
Flags: X - disabled, I - invalid; D - dynamic
0 D ;;; special dummy rule to show fasttrack counters
chain=prerouting action=passthrough

1 ;;; Debug DHCP raw output
chain=output action=log src-port=67,68 dst-port=67,68 log=no log-prefix="RAW-output-67: " protocol=udp

@CGGXANNX Thank you, raw sockets, who’d have thought…

So… is it possible to catch and send these packets using some trick or is it not because of raw sockets?

Only now I was able to return to this, and yet wanted to spread the config on a single RouterOS host, sth like that:

local relay, public facing → localhost with DHCP bound server, hidden from the broadcast domain, answering only relayed queries.

I tried isolating the DHCP server on an separate interface (vlan, bridge). This didn’t work either but in some strange way:

  • DHCP relay works OK, eg. it relays to an indicated IP address (either it is local RouterOS or an external host)
  • ROuterOS DHCP server would not get these packets. For external server it works, so I don’t see why this wouldn’t work for a single RouterOS.

…but maybe it is terrible mishap to run dhcp relay and server this way, on a single host, even if its isolated it would bound to all itnerrfaces?

are the raw sockets so greedy that VRF isolation wouldn’t help?

Just wanted to summarize limitations here, before I forget:

  • RouterOS cannot in any way track outbound packets as created by local DHCP server in Netfilter (or whatever ROuterOS uses). Creating any firewall rule would not reveal any outbound DHCP traffic, no matter what I did. This sounds very much as limitation, but still a feature, not a bug.

Hopefully this statement is right. Reason could be that raw sockets are used by DHCP server.

Workarounds:

  • RouterOS can sniff these outbound DHCP packets and sends them over TZSP protocol to a remote host. This feature works OK. TZSP allows to send the broadcasts and is generally pleasant to use. Beware: when taking about the TZSP, please note that it is a Packet Sniffer in Mikrotik, and not firewall TZSP matcher.

    This TZSP matcher in firewal presumably works OK, but I suspect since Netfilter does not see any DHCP outbound packets, TSZP consequently does not forward these non-existing-for-firewall packets :slight_smile:

I can say this is solved, hopefully this helps anyone in the future.

I guess that makes sense. I use TZSP a lot, and does make quick work of packet sniffing. One thing to watch is I believe sniffer does prevent fastpath when enabled, at least on some devices.
.