In message <https://marc.info/?l=openbsd-misc&m=162550822403762&w=1> (date 2021-07-05) I wrote: > Has anyone used an OpenBSD firewall (pf) to protect an Ooma Telo VOIP > phone system from internet attacks? If so, how did you do it? More > generally, how do people protect VOIP phone systems (regardless of brand) > from internet attacks?
There were various helpful replies in that thread, but I wasn't able to complete my firewall upgrade at that time. I've recently returned to this project, and after a bit of fiddling around I'm please to report a successful outcome. For the benefit of anyone else trying to protect a similar VOIP system, here's a summary of what I've done. My network topology is this: +-------------------+ (internet) --------| ISP-provided ADSL | | modem/router | +-------------------+ | | +----------+ +-----------+ | OpenBSD |--------| Omma Telo |.......... analog | firewall | | VOIP box | telephones +----------+ +-----------+ | | +--------+ | | | Wifi |-----+ +------ wired client | access | (or network switch for | point | multiple wired clients) +--------+ One of my overall goals in trying to design this system is to not trust either the ISP-provided ADSL modem/router (the "ISP box") or the Ooma Telo VOIP box any more than necessary -- they're both probably running out-of-date embedded Linux systems, and could well be hacked at some point. Notably, I'd rather not trust the ISP box's DNS service, and I'd like to prevent either the ISP box or the VOIP box from being able to probe or attack my other local computers. Therefore, the OpenBSD firewall (a PC Engines apu4d4) has separate physical network interfaces to talk to the ISP box, the VOIP box, a wifi access point (for other local computers that want internet access) and a wired client (another local computer or computers that wants internet access). The firewall gets a dynamic address on its "outside" interface via DHCP from the ISP box. The firewall assigns distinct /26 subnets of the 192.168.*.* address space to clients connecting via its three internal interfaces ("wired", "wifi", and "voip"). The firewall runs dhcpd to assign dynamic IP addresses within those subnets, and to advertise itself as a DNS server to all the local clients and the VOIP box. The firewall also runs unbound to provide caching DNS service to the VOIP box and the local computers, and to do secure DNS-over-TCP to an upstream DNSSEC provider. (That way I don't need to trust the ISP box's DNS service.) The Ooma VOIP documentation says it uses the following ports: outgoing UDP/TCP 53, 1194, 1294 outgoing TCP 80, 110, 443 outgoing UDP 67, 123, 3480 incoming UDP 10000 to 30000 but doesn't have much to say about NAT-vs-dynamically-chosen-ports issues. I was pleasantly surprised to find that it works fine through the firewall's NAT. I give the relevant parts of the firewall's /etc/pf.conf below. This doesn't give perfect protection (e.g., the ISP box could still insert nastygram packets into non-encrypted connections), but it does offer fairly good protection, hopefully enough to protect me from typical "mass attacks". Unless the ISP box meddles in the traffic quite heavily, the OpenBSD firewall's NAT and "modulate state" should ensure that all traffic to/from the outside world has high-entropy initial TCP sequence numbers and ports (for improved resistance to TCP-sequence-guessing attacks). --- begin firewall /etc/pf.conf --- # uncomment one of the following two lines # to configure logging for the main wired/wifi subnets MAYBE_LOG_MAIN = "" # uncomment for no logging #MAYBE_LOG_MAIN = "log" # uncomment for logging # uncomment one of the following two lines # to configure logging for the voip subnet MAYBE_LOG_VOIP = "" # uncomment for no logging #MAYBE_LOG_VOIP = "log" # uncomment for logging # uncomment one of the following two lines # to configure logging for the default block rule MAYBE_LOG_BLOCK = "" # uncomment for no logging #MAYBE_LOG_BLOCK = "log" # uncomment for logging ################################################################################ if_outside = "em0" if_wired = "em1" if_wifi = "em2" if_voip = "em3" if_internal = "{" $if_wired $if_wifi $if_voip "}" if_all = "{" $if_outside $if_wired $if_wifi $if_voip "}" # last byte of ip address: # /25 /26 /27 /28 /29 /30 /31 /32 # 128 64 32 16 8 4 2 1 # so a /26 has a netmask of 255.255.255.192 = 0xffffffc0 subnet_wired = "192.168.144.0/26" # .0 to .63 subnet_wifi = "192.168.144.64/26" # .64 to .127 subnet_wired_or_wifi = "192.168.144.0/25" # .0 to .127 subnet_voip = "192.168.144.128/26" # .128 to .191 subnet_internal = "192.168.144.0/24" # .0 to .255 ################################################################################ set skip on lo block return $MAYBE_LOG_BLOCK # allow incoming ipv4 connections from any local machine # to the firewall itself (localhost or any of the firewall's internal addresses) # ... this is used for for dns lookups # and for ssh from local machines to the firewall pass in $MAYBE_LOG_MAIN quick on $if_wired inet from $subnet_wired \ to { localhost $if_internal } pass in $MAYBE_LOG_MAIN quick on $if_wifi inet from $subnet_wifi \ to { localhost $if_internal } pass in $MAYBE_LOG_VOIP quick on $if_voip inet from $subnet_voip \ to { localhost $if_internal } # allow outgoing ipv4 connections from the firewall itself to any address # ... traffic from the firewall itself may appear to come from localhost # or from an interface address pass out $MAYBE_LOG_MAIN quick on $if_internal inet \ from { localhost $if_internal } pass out $MAYBE_LOG_MAIN quick on $if_outside inet \ from { localhost ($if_outside ) } ## ## firewall rules to pass traffic from/to the wired/wifi subnets omitted here ## # allow ipv4 connections from the voip subnet # (but only the protocols/ports documented for our Ooma voip box) # to/from the outside world and NAT these pass in $MAYBE_LOG_VOIP quick on $if_voip inet \ proto udp \ from $subnet_voip to !$subnet_internal \ port { 53 1194 1294 67 123 3480 10000:20000 } pass in $MAYBE_LOG_VOIP quick on $if_voip inet \ proto tcp \ from $subnet_voip to !$subnet_internal \ port { 53 1194 1294 80 110 443 } pass out $MAYBE_LOG_VOIP quick on $if_voip inet \ proto udp \ to $subnet_voip \ port 49000:50000 pass out $MAYBE_LOG_VOIP quick on $if_outside inet \ from $subnet_voip to !$subnet_internal \ nat-to ($if_outside) modulate state --- end firewall /etc/pf.conf --- -- -- "Jonathan Thornburg [remove -color to reply]" <jthorn4...@gmail-pink.com> on the west coast of Canada, eh? "Why would we install sewers in London? Everyone keeps getting cholera again and again so there's obviously no reason to install sewers. We just need to get used to this as the new normal." -- 2022-07-25 tweet by "Neoliberal John Snow"