Thank you Florian and Frank for your suggestions. Yes, I found it now
also in the man page under "RAW PAYLOAD EXPRESSION".
I tested step for step:
ip daddr $IP4_IF2 meta l4proto {udp, tcp} @th,16,16 {69, 23} accept
ip daddr $IP4_IF2 meta l4proto . @th,16,16 {udp . 69, tcp . 23} accept
ip daddr $IP4_IF2 meta l4proto . @th,16,16 @CONCATENATED_SET_3 accept
and verified with netcat - it is functional in this way.
Could there be issues with conntrack, nat, etc with this approach?
I will test it in the next days.
Firstly I will start with separate UDP and TCP service groups.
Nb. I use separate ipv4 and ipv6 tables, because they are really
different protocols. In my experience the mixing leads often to
overlooked security flaws - I am working as pentester occasionally.