This is a discussion on testing pf rulesets within the comp.unix.bsd.openbsd.misc forums, part of the OpenBSD category; --> Hello! Is there a way to test packet filter rules using a tool comparable to ipftest? Ok, I know ...
| |||||||
| Register | FAQ | Members List | Calendar | Search | Today's Posts | Mark Forums Read |
| ||||
| Hello! Is there a way to test packet filter rules using a tool comparable to ipftest? Ok, I know that I can submit my rulesets to this newsgroup or to a pf related mailing list to be evaluated by some kindly reader, but I do not want to waste the time of other people checking my rules if I can do this work myself. I can, however, make the rulesets publicly available to other people. I am now working on a set of rules for pf and ipf[*] targeted to workstations or servers (not firewalls). Before submitting these rulesets I want to make sure that they will work as expected. My goal is closing both well-known (from 0 up to 1023) and registered (in the range 1024-49151) ports by default; opening only these ports that should offer services to other machines. For dynamic and/or private ports (those between 49152 and 65535) I think that a good strategy would be the next one: - these ports must be closed by default. - when a client opens a connection to a remote machine from a dynamic/private port, only the server reached by the client should be able to connect to the client (i.e., these ports should be reachable only when the connection has been established from the workstation/server). ssh is very different. I am seriously considering either adding a special rule for the ssh clients or setting "UsePrivilegedPort" to "no". I certainly do not understand why using registered ports is more secure, as we certainly should not trust on a remote client just because it is able to open privileged ports instead of dynamic/private ones. I suppose that the cleaner answer will be adding a rule for the ports range used by ssh clients, as it will make this ruleset more portable. On the other hand, it is better setting up a ruleset that does not require changing the default behaviour of an operating system component. [*] support for ipf is important as there are systems that provide ipf by default. My main concern are not BSD systems but other operating systems (as Solaris, IRIX or HP-UX) that offer too many services by default. Some services cannot be closed without a significant lose of functionality but should not be widely open either (e.g., IndyCams require a service listening to the external network on IRIX). Cheers, Igor. |
| |||
| Igor Sobrado <igor@nospam.invalid> wrote: > Hello! > > Is there a way to test packet filter rules using a tool comparable > to ipftest? Ok, I know that I can submit my rulesets to this newsgroup > or to a pf related mailing list to be evaluated by some kindly reader, > but I do not want to waste the time of other people checking my rules if > I can do this work myself. I can, however, make the rulesets publicly > available to other people. I am now working on a set of rules for pf > and ipf[*] targeted to workstations or servers (not firewalls). Before > submitting these rulesets I want to make sure that they will work as > expected. > > My goal is closing both well-known (from 0 up to 1023) and registered > (in the range 1024-49151) ports by default; opening only these ports > that should offer services to other machines. For dynamic and/or > private ports (those between 49152 and 65535) I think that a good > strategy would be the next one: > > - these ports must be closed by default. > - when a client opens a connection to a remote machine from a > dynamic/private port, only the server reached by the client should > be able to connect to the client (i.e., these ports should be > reachable only when the connection has been established from the > workstation/server). I don't know at all about ipf, but isn't that what pf's 'keep state' is for? > ssh is very different. I am seriously considering either adding a > special rule for the ssh clients or setting "UsePrivilegedPort" to "no". > I certainly do not understand why using registered ports is more secure, > as we certainly should not trust on a remote client just because it is > able to open privileged ports instead of dynamic/private ones. I suppose > that the cleaner answer will be adding a rule for the ports range used > by ssh clients, as it will make this ruleset more portable. On the other > hand, it is better setting up a ruleset that does not require changing > the default behaviour of an operating system component. From ssh(1): UsePrivilegedPort Specifies whether to use a privileged port for outgoing connec- tions. The argument must be ``yes'' or ``no''. The default is ``no''. If set to ``yes'', ssh(1) must be setuid root. Note that this option must be set to ``yes'' for RhostsRSAAuthentication with older servers. In pf, 'pass out on $some_if to <ssh_servers> port ssh keep state'. Why not? >[*] support for ipf is important as there are systems that provide > ipf by default. My main concern are not BSD systems but other > operating systems (as Solaris, IRIX or HP-UX) that offer too > many services by default. Some services cannot be closed without > a significant lose of functionality but should not be widely > open either (e.g., IndyCams require a service listening to > the external network on IRIX). Okay, but I don't know ipf and have no particular reason to try to learn it; I presume the same attitude applies to quite a few OpenBSD people. Joachim |
| |||
| jKILLSPAM.schipper@math.uu.nl wrote: > Igor Sobrado <igor@nospam.invalid> wrote: >> My goal is closing both well-known (from 0 up to 1023) and registered >> (in the range 1024-49151) ports by default; opening only these ports >> that should offer services to other machines. For dynamic and/or >> private ports (those between 49152 and 65535) I think that a good >> strategy would be the next one: >> >> - these ports must be closed by default. >> - when a client opens a connection to a remote machine from a >> dynamic/private port, only the server reached by the client should >> be able to connect to the client (i.e., these ports should be >> reachable only when the connection has been established from the >> workstation/server). > > I don't know at all about ipf, but isn't that what pf's 'keep state' is > for? Indeed. But the final ruleset can be complex. A way to check these rules (apart of translating all the rules to ipf and using ipftest) would be great. Even if the initial set of rules is simple (all connections blocked by default, dynamic/private ports with the behaviour shown here), the pf configuration file can grow and become complex. It would be nice being able to check the proposed configuration files, apart of translating the rules to ipf or using nmap. >> ssh is very different. I am seriously considering either adding a >> special rule for the ssh clients or setting "UsePrivilegedPort" to "no". >> I certainly do not understand why using registered ports is more secure, >> as we certainly should not trust on a remote client just because it is >> able to open privileged ports instead of dynamic/private ones. I suppose >> that the cleaner answer will be adding a rule for the ports range used >> by ssh clients, as it will make this ruleset more portable. On the other >> hand, it is better setting up a ruleset that does not require changing >> the default behaviour of an operating system component. > > From ssh(1): > UsePrivilegedPort > Specifies whether to use a privileged port for outgoing connec- > tions. The argument must be ``yes'' or ``no''. The default is > ``no''. If set to ``yes'', ssh(1) must be setuid root. Note > that this option must be set to ``yes'' for > RhostsRSAAuthentication with older servers. > > In pf, 'pass out on $some_if to <ssh_servers> port ssh keep state'. Why > not? That is the reason I am considering using "UsePrivilegedPort", it is not only documented on ssh(1) but it is also the first question on the OpenSSH FAQ. The real issue is not passing traffic to port 22, but sending traffic out of the machine (I want to block both incoming and outgoing packets by default). >>[*] support for ipf is important as there are systems that provide >> ipf by default. My main concern are not BSD systems but other >> operating systems (as Solaris, IRIX or HP-UX) that offer too >> many services by default. Some services cannot be closed without >> a significant lose of functionality but should not be widely >> open either (e.g., IndyCams require a service listening to >> the external network on IRIX). > > Okay, but I don't know ipf and have no particular reason to try to learn > it; I presume the same attitude applies to quite a few OpenBSD people. Not a problem at all. I have some (limited) knowledge on ipf too. It is just that I do not trust on a ruleset translation between pf and ipf (even worse if that translation is done by me!), a way to test these ruleset on OpenBSD would be great. On the other hand, I want to write equivalent rulesets for ipf and pf on this case (I try to protect workstations that can be running a lot of different Unix flavours where pf is not available), for other tasks (I will build a firewall on my soekris appliance very soon) I will use pf only. I am just asking about a way to test rulesets natively on pf; it should be clear (and I supposed it was) that I am not asking about ipf. Cheers, Igor. |
| |||
| Igor Sobrado <igor@nospam.invalid> wrote: > jKILLSPAM.schipper@math.uu.nl wrote: >> Igor Sobrado <igor@nospam.invalid> wrote: >>> My goal is closing both well-known (from 0 up to 1023) and registered >>> (in the range 1024-49151) ports by default; opening only these ports >>> that should offer services to other machines. For dynamic and/or >>> private ports (those between 49152 and 65535) I think that a good >>> strategy would be the next one: >>> >>> - these ports must be closed by default. >>> - when a client opens a connection to a remote machine from a >>> dynamic/private port, only the server reached by the client should >>> be able to connect to the client (i.e., these ports should be >>> reachable only when the connection has been established from the >>> workstation/server). >> >> I don't know at all about ipf, but isn't that what pf's 'keep state' is >> for? > > Indeed. But the final ruleset can be complex. A way to check these > rules (apart of translating all the rules to ipf and using ipftest) > would be great. Even if the initial set of rules is simple (all > connections blocked by default, dynamic/private ports with the > behaviour shown here), the pf configuration file can grow and become > complex. It would be nice being able to check the proposed configuration > files, apart of translating the rules to ipf or using nmap. pfctl -nf /some/file does a basic syntax check, which does not of course prove your rules correct but will at least catch some mistakes. Otherwise, running an OpenBSD instance in a emulator (qemu, vmware, or - hopefully soon - Xen) might be good for helping. However, to the best of my knowledge, there is no tool corresponding to ipftest currently available on OpenBSD. >>> ssh is very different. I am seriously considering either adding a >>> special rule for the ssh clients or setting "UsePrivilegedPort" to "no". >>> I certainly do not understand why using registered ports is more secure, >>> as we certainly should not trust on a remote client just because it is >>> able to open privileged ports instead of dynamic/private ones. I suppose >>> that the cleaner answer will be adding a rule for the ports range used >>> by ssh clients, as it will make this ruleset more portable. On the other >>> hand, it is better setting up a ruleset that does not require changing >>> the default behaviour of an operating system component. >> >> From ssh(1): >> UsePrivilegedPort >> Specifies whether to use a privileged port for outgoing connec- >> tions. The argument must be ``yes'' or ``no''. The default is >> ``no''. If set to ``yes'', ssh(1) must be setuid root. Note >> that this option must be set to ``yes'' for >> RhostsRSAAuthentication with older servers. >> >> In pf, 'pass out on $some_if to <ssh_servers> port ssh keep state'. Why >> not? > > That is the reason I am considering using "UsePrivilegedPort", it is > not only documented on ssh(1) but it is also the first question on > the OpenSSH FAQ. The real issue is not passing traffic to port 22, > but sending traffic out of the machine (I want to block both incoming > and outgoing packets by default). It appears we are not understanding each other. pf(4) allows you to allow connections to port 22 on either all hosts or a list/table of hosts; this is about *outgoing* connections, of course - incoming connections can be treated similarly, but we are not talking about them here. When using the 'keep state' mechanism, the return traffic of the connection is also taken care of - there is no need to explicitly allow traffic back to some high-numbered port. This is done with 'pass out on $some_if to <ssh_servers> port ssh keep state', as noted above. I do not understand what else you want to achieve. Joachim |
| |||
| jKILLSPAM.schipper@math.uu.nl wrote: > Igor Sobrado <igor@nospam.invalid> wrote: >> >> Indeed. But the final ruleset can be complex. A way to check these >> rules (apart of translating all the rules to ipf and using ipftest) >> would be great. Even if the initial set of rules is simple (all >> connections blocked by default, dynamic/private ports with the >> behaviour shown here), the pf configuration file can grow and become >> complex. It would be nice being able to check the proposed configuration >> files, apart of translating the rules to ipf or using nmap. > > pfctl -nf /some/file does a basic syntax check, which does not of course > prove your rules correct but will at least catch some mistakes. Thanks a lot for this excellent advice. Indeed, it is the way I discovered some days ago that groups (in the *ipf* sense) are not available in pf... at that time I supposed that a mostly portable ruleset (e.g., not using lists) and some minor changes to take advantage of pf improvements (e.g., scrubbing) was all we need. But all rulesets I wrote in the past use groups. Now I am looking at the excellent FAQ, looking for information about how "anchors" work. I like ipf groups *not* because it is a way to optimize rules (I certainly prefer automatic optimization!); for me, the main advantage of groups is that it helps organizing rulesets in a logical structure. I think that "anchors" are more powerful to achieve this goal. It seems that anchors have all the advantages of ipf groups but let the computer to optimize rulesets. Another excellent design decision. > Otherwise, running an OpenBSD instance in a emulator (qemu, vmware, or > - hopefully soon - Xen) might be good for helping. However, to the best > of my knowledge, there is no tool corresponding to ipftest currently > available on OpenBSD. Well, as you say I can set up the firewall on some machine. Now tools like netstat and nmap can do an excellent work analyzing our ruleset. I will do it, thanks! >> That is the reason I am considering using "UsePrivilegedPort", it is >> not only documented on ssh(1) but it is also the first question on >> the OpenSSH FAQ. The real issue is not passing traffic to port 22, >> but sending traffic out of the machine (I want to block both incoming >> and outgoing packets by default). > > It appears we are not understanding each other. > > pf(4) allows you to allow connections to port 22 on either all hosts or > a list/table of hosts; this is about *outgoing* connections, of course - > incoming connections can be treated similarly, but we are not talking > about them here. > > When using the 'keep state' mechanism, the return traffic of the > connection is also taken care of - there is no need to explicitly allow > traffic back to some high-numbered port. > > This is done with 'pass out on $some_if to <ssh_servers> port ssh keep > state', as noted above. I do not understand what else you want to > achieve. I know that a "keep state" would open a (previously closed) port to the machine on the other end of the communication channel. In other words, if port "x" on machine "A" establishes a communication to port "y" on machine "B", all traffic with source on B:y is automatically accepted by A:x -- no need to explicitly allow connections from B. My problem is that I do not want to set a rule like "block in all", but a rule like "block all" (both incoming/outgoing traffic blocked by default), except for high-numbered ports (where clients should be able to establish connections with remote servers, but only with these servers). I do not want to expose a client if it is not required at all (perhaps am I a bit paranoid?). My goal is that a server (or a client using a port < 49152, except an ssh client, of course) will not be able to establish a connection with a remote machine without being authorized. Certainly "keep state" will do the work if all traffic with source on the local workstation is allowed to reach the world. Perhaps it is a too complex design to win too few, and it is better stay at a classic "all traffic arriving to our machine blocked by default, all traffic with source on our machine allowed". What do you think? Cheers, Igor. |
| |||
| Igor Sobrado <igor@nospam.invalid> wrote: > jKILLSPAM.schipper@math.uu.nl wrote: >> Igor Sobrado <igor@nospam.invalid> wrote: >>> That is the reason I am considering using "UsePrivilegedPort", it is >>> not only documented on ssh(1) but it is also the first question on >>> the OpenSSH FAQ. The real issue is not passing traffic to port 22, >>> but sending traffic out of the machine (I want to block both incoming >>> and outgoing packets by default). >> >> It appears we are not understanding each other. >> >> pf(4) allows you to allow connections to port 22 on either all hosts or >> a list/table of hosts; this is about *outgoing* connections, of course - >> incoming connections can be treated similarly, but we are not talking >> about them here. >> >> When using the 'keep state' mechanism, the return traffic of the >> connection is also taken care of - there is no need to explicitly allow >> traffic back to some high-numbered port. >> >> This is done with 'pass out on $some_if to <ssh_servers> port ssh keep >> state', as noted above. I do not understand what else you want to >> achieve. > > I know that a "keep state" would open a (previously closed) port to > the machine on the other end of the communication channel. In other > words, if port "x" on machine "A" establishes a communication to > port "y" on machine "B", all traffic with source on B:y is automatically > accepted by A:x -- no need to explicitly allow connections from B. > > My problem is that I do not want to set a rule like "block in all", > but a rule like "block all" (both incoming/outgoing traffic blocked > by default), except for high-numbered ports (where clients should be > able to establish connections with remote servers, but only with these > servers). I do not want to expose a client if it is not required at all > (perhaps am I a bit paranoid?). > > My goal is that a server (or a client using a port < 49152, except an ssh > client, of course) will not be able to establish a connection with a remote > machine without being authorized. > > Certainly "keep state" will do the work if all traffic with source on > the local workstation is allowed to reach the world. > > Perhaps it is a too complex design to win too few, and it is better > stay at a classic "all traffic arriving to our machine blocked by > default, all traffic with source on our machine allowed". What do > you think? If you mean what I think you mean, it's quite easy. Most pf rulesets I write are variants on the following: ** ext_if="rl0" int_if="rl1" tcp_out = { http https 8080 } udp_out = ntp # or { ntp } tcp_in_local = ssh #udp_in_local = serverA = 192.168.0.4 tcp_in_serverA = { smtp imap } udp_in_serverA = { domain } # DNS set skip on lo scrub in antispoof quick for { lo $int_if } block log all # You might not want to log in the long run, but it is # very useful for debugging pass proto tcp from { $int_if:network $ext_if } to port $tcp_out \ keep state # or modulate state pass proto udp from { $int_if:network $ext_if } to port $tcp_out \ keep state pass proto tcp to $serverA port $tcp_in_serverA keep state pass proto udp to $serverA port $udp_in_serverA keep state pass proto tcp to $ext_if port $tcp_in_local keep state #pass proto udp to $ext_if port $udp_in_local keep state ** Of course, the above is simplistic - one often needs NAT, usually ftp-proxy (note this has been rewritten for 3.9; I'm not sure what version is used by other systems, if any), and so on - but it does show that filtering both incoming and outgoing traffic is quite easy. A more usual setup is to 'pass all on $int_if' and then filter on the outgoing interface; this is quicker, I suppose, but some care needs to be taken not to open up the internal interface of the firewall to the entire network - not that that is too dangerous, but it isn't required. Joachim |
| |||
| jKILLSPAM.schipper@math.uu.nl wrote: > > If you mean what I think you mean, it's quite easy. Most pf rulesets I > write are variants on the following: > [...] > > Of course, the above is simplistic - one often needs NAT, usually > ftp-proxy (note this has been rewritten for 3.9; I'm not sure what > version is used by other systems, if any), and so on - but it does show > that filtering both incoming and outgoing traffic is quite easy. > > A more usual setup is to 'pass all on $int_if' and then filter on the > outgoing interface; this is quicker, I suppose, but some care needs to > be taken not to open up the internal interface of the firewall to the > entire network - not that that is too dangerous, but it isn't required. Hi, Joachim. An *excellent* advice, indeed! Certainly logging all traffic by default is very useful (someone can miss, we say, some rules for the resolver). Mistakes will be quickly discovered by logging all blocked traffic. I will print your post right now and store it for future reference. The skeleton you provided is an exceptional starting point for a firewall. Thanks again! I think that I will not care about NAT at this level, I have a soekris net4801 (currently running 3.9) that will perform this task better. In fact, I am planning to add some subnets to that excellent embedded computer too (it has an additional two-port NIC installed). I am just waiting until an appropriate 2.5" HDD arrives (it currently has a 60 GB Travelstar drive, I have just asked for a 40 GB enhanced availability drive... SMART starts complaining about the time the HDD is turned on!). I want to have NAT and a decent ruleset when the new HDD arrives, as the machine should stay up 24/7. On the question that started this thread (checking rules), I find right now that nmap supports a very interesting option (-sA) to map out firewall rulesets. This option will certainly provided additional feedback on the current ruleset (better than the one the usual "nmap -A ..." or "nmap -sU ..." provides). Thank you very much! Igor. |
| |||
| Igor Sobrado <igor@nospam.invalid> wrote: > jKILLSPAM.schipper@math.uu.nl wrote: >> >> If you mean what I think you mean, it's quite easy. Most pf rulesets I >> write are variants on the following: >> > [...] >> >> Of course, the above is simplistic - one often needs NAT, usually >> ftp-proxy (note this has been rewritten for 3.9; I'm not sure what >> version is used by other systems, if any), and so on - but it does show >> that filtering both incoming and outgoing traffic is quite easy. >> >> A more usual setup is to 'pass all on $int_if' and then filter on the >> outgoing interface; this is quicker, I suppose, but some care needs to >> be taken not to open up the internal interface of the firewall to the >> entire network - not that that is too dangerous, but it isn't required. > > Hi, Joachim. > > An *excellent* advice, indeed! Certainly logging all traffic by default > is very useful (someone can miss, we say, some rules for the resolver). > Mistakes will be quickly discovered by logging all blocked traffic. > I will print your post right now and store it for future reference. > > The skeleton you provided is an exceptional starting point for a firewall. > Thanks again! > > I think that I will not care about NAT at this level, I have a soekris > net4801 (currently running 3.9) that will perform this task better. > In fact, I am planning to add some subnets to that excellent embedded > computer too (it has an additional two-port NIC installed). I am > just waiting until an appropriate 2.5" HDD arrives (it currently has > a 60 GB Travelstar drive, I have just asked for a 40 GB enhanced > availability drive... SMART starts complaining about the time the HDD > is turned on!). I want to have NAT and a decent ruleset when the new > HDD arrives, as the machine should stay up 24/7. For maximum reliability, one could consider carp(4), pfsync(4), and such. More information can be found in the FAQ. (Disclaimer: while this should work really well, one should probably run -current if one wishes to use sasyncd(8), and I do not have personal experience with either.) Joachim |
| |||
| Igor Sobrado <igor@nospam.invalid> wrote: > jKILLSPAM.schipper@math.uu.nl wrote: >> >> If you mean what I think you mean, it's quite easy. Most pf rulesets I >> write are variants on the following: >> > [...] >> >> Of course, the above is simplistic - one often needs NAT, usually >> ftp-proxy (note this has been rewritten for 3.9; I'm not sure what >> version is used by other systems, if any), and so on - but it does show >> that filtering both incoming and outgoing traffic is quite easy. >> >> A more usual setup is to 'pass all on $int_if' and then filter on the >> outgoing interface; this is quicker, I suppose, but some care needs to >> be taken not to open up the internal interface of the firewall to the >> entire network - not that that is too dangerous, but it isn't required. > > Hi, Joachim. > > An *excellent* advice, indeed! Certainly logging all traffic by default > is very useful (someone can miss, we say, some rules for the resolver). > Mistakes will be quickly discovered by logging all blocked traffic. One more tidbit: note that while one can always use tcpdump -envvvi pflog0 -s 200, packets are not logged to disk unless pflogd(8) is used - i.e., 'block log all' only sends packets to the logging interface, pflog0 by default. Joachim |
| ||||
| jKILLSPAM.schipper@math.uu.nl wrote: > > For maximum reliability, one could consider carp(4), pfsync(4), and > such. More information can be found in the FAQ. (Disclaimer: while this > should work really well, one should probably run -current if one wishes > to use sasyncd(8), and I do not have personal experience with either.) I have read excellent comments on carp(4), but pfsync(4) is unknown for me. carp(4) should not be too difficult to configure, and it seems very useful at least on the net4801. This soekris will be become a firewall and router (I think that at this time it will be very difficult moving these functions to different network appliances). In fact, there is an example on using carp(4) on appliances with multiple network interfaces on the manual page. Thanks! Igor. |