Solved IPFW Log Session Setup only

I'm fairly new to IPFW but have read the various examples and the manual page carefully. I can't seem to find a way to log a successful connection without logging all subsequent packets. I thought the best way would be using keep-state but that doesn't work the way I intended. With IPFILTER there is a log first keyword to allow this functionality.

Here is an abbreviated set of my rules:
Code:
01100 check-state :default
02500 allow log logamount 100 tcp from 192.0.2.100 to me 22 setup keep-state :default
65500 deny log logamount 500 ip from any to any
65535 deny ip from any to any

Is it possible to get this functionality, logging only the first packet of a connection, with IPFW?

Thanks in advance,

Bob
 
Last edited:
[...] I can't seem to find a way to log a successful connection without logging all subsequent packets.

Here is an abbreviated set of my rules:
Code:
01100 check-state :default
02500 allow log logamount 100 tcp from 192.0.2.100 to me 22 setup keep-state :default
65500 deny log logamount 500 ip from any to any
65535 deny ip from any to any
Is it possible to get this functionality, logging only the first packet of a connection, with IPFW?
Ok, I did come up with a kludge that seems to work using two rules but I’d love to hear of a single rule solution as my kludge doubles the rules for each host (or requires me to convert to tables).

02500 allow log logamount 100 tcp from 192.0.2.100 to me 22 setup
02510 allow tcp from 192.0.2.100 to me 22
 
Ok, I did come up with a kludge that seems to work using two rules but I’d love to hear of a single rule solution as my kludge doubles the rules for each host (or requires me to convert to tables).
Tables are very useful, but don't seem applicable to this situation per se.

You can add 'count log ...' rules per host you want to log connections for, then later use a single 'allow ... keep-state' rule for all hosts in a subnet (or list) - assuming that's what you're intending?

That way you only need add one extra rule - though unless you're pumping many kpkts/sec the extra execution time is irrelevant.

However you do need to put such 'count' rules and other static rules before any check- or keep-state rules that cause skipping over other rules.

You'll also need to do subnet rule counting before any NAT while src addresses are local, if that's the case here, given the 192.0.2/24 subnet.

02500 allow log logamount 100 tcp from 192.0.2.100 to me 22 setup
02510 allow tcp from 192.0.2.100 to me 22
Sure, if you prefer stateless rules, but you'd want to add 'established' to the latter rule; it's a different approach and only you know what suits you.

So, based on your first post:
Code:
00500 count log logamount 100 tcp from 192.0.2.100 to me 22 setup // stateless
# other count rules before ...
01100 check-state :default
02500 allow tcp from 192.0.2.100 to me 22 setup keep-state :default
65500 deny log logamount 500 ip from any to any
65535 deny ip from any

If doing a whole or partial subnet, instead perhaps:
Code:
02500 allow tcp from 192.0.2.100/24 to me 22 setup keep-state :default

If you wanted traffic accounting for each host - otherwise all traffic accumulates, mixed in- and outbound on one keep-state rule - then add other rules for each, e.g. perhaps:

Code:
00501 count tcp from 192.0.2.100 to me 22
00502 count tcp from me 22 to 192.0.2.100

HTH, Ian
 
[...] You can add 'count log ...' rules per host you want to log connections for, then later use a single 'allow ... keep-state' rule for all hosts in a subnet (or list) - assuming that's what you're intending?
[...]

I hadn't realized that one could use count as kind of a no-op rule. The only downside of the count vs allow log rule is it shows up in the log tagged as count vs accept. I find the accept a little better as a documentary reminder of what I was logging.

Sure, if you prefer stateless rules, but you'd want to add 'established' to the latter rule; it's a different approach and only you know what suits you.
[...]
I will look into adding established to the rule and make sure it doesn't have any side effects. I was seeing some dropped connection wierdness with my ssh connections with the keep-state dynamic rules and was thinking perhaps they were expiring too quickly and noticed that the rule set in the default workstation profile of rc.firewall used established to allow back in outgoing connections.

I think I settled on the following 2 rules using a table named ALLOW that has IPV4 and IPV6 individual addresses and net blocks in it.

Code:
02450 allow log logamount 100 tcp from table(ALLOW) to me 22 setup
02500 allow tcp from table(ALLOW) to me 22

At least this way I go from one rule to two instead of six to 12.

Thank you very much for your suggestions and comments. I did struggle a bit with placement of some of the trial rules because of where the established and keep state general rules were in the workstation standard ruleset.

Bob
 
I hadn't realized that one could use count as kind of a no-op rule. The only downside of the count vs allow log rule is it shows up in the log tagged as count vs accept. I find the accept a little better as a documentary reminder of what I was logging.
Fair enough.

I will look into adding established to the rule and make sure it doesn't have any side effects. I was seeing some dropped connection wierdness with my ssh connections with the keep-state dynamic rules and was thinking perhaps they were expiring too quickly and noticed that the rule set in the default workstation profile of rc.firewall used established to allow back in outgoing connections.
Now I know you're basing this on the workstation ruleset, it may be helpful to know where these new rules are inserted?

I likely misadvised you about where to allow established sessions, now we know you're using stateless rules (that I generally prefer) for such as ssh sessions.

I think I settled on the following 2 rules using a table named ALLOW that has IPV4 and IPV6 individual addresses and net blocks in it.

Code:
02450 allow log logamount 100 tcp from table(ALLOW) to me 22 setup
02500 allow tcp from table(ALLOW) to me 22
Problem with this is that 2500 allows packets in even before the session is established. Likely not a problem with your trusted table of hosts, but dodgy practice on the wild web.

Instead, guided by 'simple' ruleset, before 2450 add 'allow tcp from any to me established', perhaps just after the existing 'allow tcp from me to any established'. You could merge the two ('any to any') but separate traffic counts will prove useful sometimes. You could also replace 'any' with your table if appropriate.

So 'allow ... setup' rules come later - again, study 'simple' for examples, bearing in mind that's for a LAN gateway as well as a public facing server.

At least this way I go from one rule to two instead of six to 12.
Tables are good, fast, and can be updated out of band, i.e. without reloading rules.

Thank you very much for your suggestions and comments. I did struggle a bit with placement of some of the trial rules because of where the established and keep state general rules were in the workstation standard ruleset.
Yes there's a bit there, and handling both methods can be tricky. You could adapt the _myservices & _allowservices section to log 'setup' packets there also.

cheers, Ian
 
Problem with this is that 2500 allows packets in even before the session is established. Likely not a problem with your trusted table of hosts, but dodgy practice on the wild web.
I like doing this the 'right' way where possible. I've actually put the 'allow tcp from any to me established' just after the one in the other direction as you suggested and have had no problems with my rules working.

I do have a best practice advice followup question. Originally I tried to leave the standard rc.firewall unmolested and placed my ALLOW table creation and a few modified rules in /etc/rc.local which I verified happens later in the startup process. I kind of wish the standard /etc/rc.firewall had a callout to a pre-script and a post-script that would allow one to initialize tables and modify rules.

Now so I can carefully place the established incoming rule I have gone ahead and edited rc.firewall to add my lines.

Do you have any advice on augmentation or just complete replacement of rc.firewall.

Thanks again for your help.

Bob
 
I do have a best practice advice followup question. Originally I tried to leave the standard rc.firewall unmolested and placed my ALLOW table creation and a few modified rules in /etc/rc.local which I verified happens later in the startup process. I kind of wish the standard /etc/rc.firewall had a callout to a pre-script and a post-script that would allow one to initialize tables and modify rules.

There is, though I've never used it. In the control script /etc/rc.d/ipfw see ipfw_poststart() which will run any scripts in ${firewall_coscripts} - noting that /etc/rc.d/natd is prepended as the first one - before the loaded ruleset is enabled.

These are expected to be in rc script (service) format and are launched with parameter 'quietstart', but I assume you could run any script/s -- not that I'm advocating using this method for inserting or deleting rules loaded as ${firewall_script}, and/or for loading tables, but you could.

Note coscripts are run again in reverse order with parameter 'quietstop', on running service ipfw stop (or 'restart'), so you'd want to guard against adding rules twice ...

Now so I can carefully place the established incoming rule I have gone ahead and edited rc.firewall to add my lines.

Do you have any advice on augmentation or just complete replacement of rc.firewall.
I used to edit rc.firewall, but now preserve and copy it to (say) /etc/rc.myfirewall and set that as ${firewall_script} and merrily hack on that.

No messiness keeping track of rule numbering (bar skipto and call targets), a diff against rc.firewall can help, and you can share the whole ruleset as needed, with or without redactions. Also, a system update may replace rc.firewall (oops!)

As ever, YMMV.

cheers, Ian
 
Back
Top