Configure Firewall to only allow incoming requests with FQDN in the request

For UCP (or the admin GUI or HTTP provisioning), this is quite complex to do with IP tables, but easy to do in Apache.

For example (showing HTTP only; HTTPS is a little more complex):

NameVirtualHost *:80

<VirtualHost *:80>
    DocumentRoot "/var/www/dummy"
    ServerName dummy
</VirtualHost>

<VirtualHost *:80>
    DocumentRoot "/var/www/html"
    ServerName my.domain.com
</VirtualHost>

Any request to other than my.domain.com, including requests to an IP address, will look in /var/www/dummy (which can be empty), because any unrecognized host defaults to the first entry.

Lots of virtual hosts at *:80 will also answer ip connections willy-nilly, a chain of failures until a url match is made or not is not a good thing, please revisit how apache reacts to a connection and what is already leaked if you 301 http to https (which is highly recommended in 2023 and above) look at your http servers logs for clues , not as common as udp/5060 and only from the clever buggers.

The :80 I posted was just an example; the OP is using port 1220, which will eliminate nearly all the noise traffic. Of course, taking the ‘dummy’ path ensures that a URL match will not occur.

IMO, there is no reason to have HTTP accessible to the outside world at all – end users should always use HTTPS. The most recent browsers will default to HTTPS if no protocol is specified. For users with older browsers, they may have to type https:// once, IMO a trivial inconvenience. However, IMO enabling HTTP access from localhost is a good idea; if something goes wrong with HTTPS, the sysadmin can use SSH port forwarding to access the GUI via HTTP.

I won’t disagree with any of that, I posit that my solution above solves all those problems and more in a far more efficient manner, if you can complete a journey in one step, then any other route should be questioned.

I would point out that the all services should remain as http if you want to tunnel and further you don’t need to eff with certs and firewall pin holes for them.

BTDT and IWFM, JM2CWAE

So here are my tests with Advanced firewall settings.

The goal is to DROP incoming requests when the PBX is accessed by its IP address and ACCEPT incoming requests when the PBX is accessed with its FQDN.

This DROP packets;
-I INPUT -p tcp --dport 1220 -m string --string “my.domain.com” --algo kmp -j DROP

the above was just a test to confirm I have functional syntax. The above successfully DROP packets that have an incoming request of “my.domain.com

now to test the DROP of packets that have an incoming request of NOT the FQDN, but instead the server’s IP address

-I INPUT -p tcp --dport 1220 -m string --string “my.domain.com” --algo kmp -j DROP
-I INPUT -p tcp --dport 1220 -m string --string “111.222.333.444” --algo kmp -j DROP

This DROPS packets when the incoming request is my.domain.com but DOES NOT drop packets if the incoming request is the server’s IP address.

Does anyone have suggestions of what I should try next?

As I said, if you are talking about HTTP, if there is no domain name there may be no character representation of the IP address; they may be using an HTTP 1.0 request, which doesn’t have a Host header.

Im doing both tests “not they”.

If I put http://my.domain.com:1220 into a browser, the access is DROP. (which is exactly the test I had hoped for).

If I put http://111.222.333.444:1220 into a browser, the access is ACCEPT (I expected the access to be DROP).

I’d still look at what is going over the wire. I think you will find that there is no host header.

Well. Ok. Lets assume no host header for when you access the server with its IP address.

How else can we do this. Block traffic arriving via the server IP and allow traffic arriving via the server FQDN?

Something like the following (which does not work by the way…)

-I INPUT -p tcp --dport 1220 -m string --string “my.domain.com” --algo kmp -j ACCEPT
-A INPUT -p tcp --dport 1220 -j DROP

The above example results in all TCP traffic on port 1220 getting dropped.
The expected result of the above example is to drop all TCP traffic on 1220 except for traffic with “my.domain.com” string match.

I tried this option to block everything except for traffic to a specific FQDN.

-A INPUT -p tcp --dport 1220 ! -m string --string “my.domain.com” --algo kmp -j DROP

This blocks traffic, including traffic pointed to my.domain.com

You might want to note that the string match rule requires the match to occur within a single packet, and only applies to that packet (the firewall doesn’t duplicate TCP). For example, if you white list the domain and someone does a long POST (or even a GET with lots of parameters), at most one packet will match.

On the basis that a re-used connection will be from the the same source, assuming GET requests aren’t excessive, matching the first packet may be enough, assuming there is a rule for that.

Also, note that, if you are using HTTPS, any clear text domain name will be put there by TLS, not by HTTP, so the precise details of the use of Host header won’t apply. I thought this was normally always done using TLS.

This approach feels like driving in a nail with a wrench. I think you’re using the wrong tools. Can you back up to the beginning and explain why you’re trying to filter like this?

The heart of the solution I am after is to not have my server respond to port sniffing and subsequent naughty activity that arrive at the server via the server’s IP address.

The war pings I am seeing & the subsequent attack is landing at the server via the servers IP address.

The FQDN is seeing no naughty inbound traffic.

Therefore I want to block traffic on certain ports that arrive via the servers IP address, and allow traffic that arrives at the same ports via the FQDN.

Its a curiosity that this works;

-A INPUT -p tcp --dport 1220 -m string --string “my.domain.com” --algo bm -j DROP

However this does not work;

-A INPUT -p tcp --dport 1220 ! -m string --string “my.domain.com” --algo bm -j DROP

If the latter worked, my goal would be accomplished.

To what ‘port sniffing’ is your server responding to?
What ‘naughty activity’ have you seen ?
Because as @billsimon suggested, iptables might not be the right tool to ‘stiffen up’ your services.

port 1220 which is where I have OpenVpn

Are you using UDP or TCP for that ? , consider wireguard as an alternative.

I’m surprised to see bad actors doing ’ naughty things’ with openvpn

You won’t be able to look inside OpenVPN packets for strings, as as they are encrypted. I don’t see how you can be matching domain names, as OpenVPN doesn’t send them for its own use.

For most protocols, the originator looks up domain names using DNS, and then only sends the IP address. This also used to be the case for HTTP, but people started running multiple servers on the same IP address.

I knew you guys would get stuck on these two points. LOL.

I have my open VPN clients using the FQDN not the IP address of the server.

And yes. for the purpose of this exercise, lets pretend that I have OpenVPN using TCP.

What this man did for SIP 5060 port, I am trying to do with the Open VPN ports.