> For the complete documentation index, see [llms.txt](https://book.bsdcn.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://book.bsdcn.org/ask/flat/chapter-31-firewalls/di-31.3-jie-ipfilter-ipf.md).

# 31.3 IPFilter (IPF)

> **Warning**
>
> The content in this section has not been tested in practice and has only been verified theoretically. Do not use it directly in a production environment! It is recommended to verify it in a test environment before deploying to production.

IPFilter (IPF) is an early cross-platform open-source firewall, authored by Darren Reed. IPF provides packet filtering and network address translation (NAT) functionality, and was originally ported to various Unix-like operating systems.

> **Note**
>
> IPFilter's upstream development has been stagnant for a long time: the last official version 5.1.2 was released in July 2012, and no new versions have been released since. OpenBSD (2001), DragonFly BSD (2011), and Oracle Solaris (from 11.4) have successively removed IPFilter. FreeBSD currently still includes IPFilter in the base system, but maintenance is limited to compatibility adaptation and security fixes, with no new features being introduced. For newly deployed firewalls, it is recommended to prioritize PF or IPFW as covered in this chapter.

IPFILTER is a kernel-level firewall that also provides a NAT mechanism, which can be controlled and monitored through user-space programs. Firewall rules can be set or removed via ipf, NAT rules can be set or removed via ipnat, runtime statistics of the IPFILTER kernel component can be printed via ipfstat, and ipmon can log IPFILTER operations to system log files.

IPF originally adopted a "last matching rule wins" rule processing logic and only used stateless rules. Since then, IPF has been extended to support the quick and keep state options.

This section focuses on IPF as it relates to FreeBSD and provides rule examples that include the quick and keep state options.

## Enabling the IPF Firewall

Enabling the IPF firewall requires preparing configuration files and starting the relevant services. The specific steps are as follows.

To enable IPF, execute the following command:

```sh
# Copy the sample file as the default configuration rule set file, otherwise no rules will take effect after ipfilter starts. The rules included in the sample file do not affect usage
cp /usr/share/examples/ipfilter/ipf.conf.sample /etc/ipf.rules
```

To configure the system to enable IPF at boot time, add the following entries to **/etc/rc.conf**. These entries will also enable logging and set `default pass all`. To change the default policy to `block all` without compiling a custom kernel, add a `block all` rule at the end of the rule set.

```ini
ipfilter_enable="YES"             # Enable ipfilter at boot time
ipfilter_rules="/etc/ipf.rules"   # Load rule definition file
ipmon_enable="YES"                # Enable ipmon at boot time
ipmon_flags="-Ds"                 # See table below
```

| `ipmon_flags` Flag | Description                         |
| ------------------ | ----------------------------------- |
| `D`                | Start in daemon mode                |
| `s`                | Log to syslog                       |
| `v`                | Log tcp window, ack, seq            |
| `n`                | Map IP addresses and ports to names |

* Start

```sh
# service ipmon enable # Enable IP monitoring logging
# service ipfilter enable # Set ipfilter to start automatically at system boot
# service ipfilter start # Start the ipfilter service
```

When loading firewall rules, specify the rule set file name with ipf. The following command can be used to replace the currently running firewall rules:

```sh
# ipf -Fa -f /etc/ipf.rules
```

Here, `-Fa` flushes all internal rule tables, and `-f` specifies the rule file to load.

This allows you to modify the custom rule set and update the running firewall by updating the rule copy without needing to restart the system. This method facilitates testing new rules and can be repeated.

If NAT functionality is needed, the following line must also be added to **/etc/rc.conf**:

```ini
gateway_enable="YES"              # Enable as LAN gateway
```

* Start ipnat:

ipnat is a component of IPF, specifically designed to maintain network address translation (NAT) rules. NAT can perform translation between internal IP addresses and public IP addresses, as well as port forwarding.

```sh
# cp /usr/share/examples/ipfilter/ipnat.conf.sample /etc/ipnat.rules   # Copy the sample file as the default configuration rule set, otherwise ipnat cannot start
# service ipnat enable   # Set ipnat to start automatically at system boot
# service ipnat start    # Start the ipnat service
```

> **Note**
>
> After the ipfilter service is restarted, ipnat must also be restarted.

The main management commands for IPF are `ipf`, `ipfstat`, and `ipnat`.

### Related File Structure

The configuration file structure for IPFilter is as follows.

```sh
/
├── etc
│   ├── ipf.rules                     # IPFilter firewall rule file
│   └── ipnat.rules                    # IPNAT forwarding rule file
└── usr
    └── share
        └── examples
            └── ipfilter
                ├── ipf.conf.sample   # IPFilter sample configuration
                └── ipnat.conf.sample # IPNAT sample configuration
```

## IPF Rule Syntax

This section explains the IPF rule syntax used for creating stateful rules. When creating rules, note that unless a rule contains the `quick` keyword, each rule is read in order, and the **last matching rule** takes effect. This means that even if the first rule matching a packet is `pass`, if a later matching rule is `block`, the packet will be dropped. Sample rule sets can be found in **/usr/share/examples/ipfilter**.

When creating rules, the `#` character is used to mark the beginning of a comment. It can also appear at the end of a rule to explain its function, or on its own line. Blank lines are ignored.

Keywords used in rules must be written in a specific order, from left to right. Some keywords are required, while the rest are optional. Certain keywords have sub-options, which themselves can be keywords and can contain further sub-options. The keyword order is as follows, where uppercase letters represent variables and lowercase letters are keywords that must precede the variables that follow them:

```ini
ACTION DIRECTION OPTIONS proto PROTO_TYPE from SRC_ADDR SRC_PORT to DST_ADDR DST_PORT TCP_FLAG|ICMP_TYPE keep state STATE
```

This section explains these keywords and their options, but is not an exhaustive list of all options.

### ACTION

The `ACTION` keyword specifies the operation to perform when a packet matches the rule. Each rule **must** have one action. The supported actions are:

| Action        | Description                                                          |
| ------------- | -------------------------------------------------------------------- |
| `block`       | Drop the packet                                                      |
| `pass`        | Allow the packet                                                     |
| `log`         | Generate a log record                                                |
| `count`       | Count packets and bytes, useful for reflecting rule match frequency  |
| `auth`        | Queue the packet for further processing by another program           |
| `call`        | Access IPF built-in functionality to perform more complex operations |
| `decapsulate` | Remove any headers to process the packet's content                   |

### DIRECTION

Next, each rule must explicitly specify the direction of traffic using one of the following keywords:

* `in`: The rule applies to incoming packets.
* `out`: The rule applies to outgoing packets.

If the system has multiple interfaces, an interface name can be specified after the direction. For example, `in on em0`.

> **Note**
>
> The `all` keyword is not a direction keyword, but rather a shorthand for address matching that matches all addresses (equivalent to `from any to any`). For example, the `all` in `block in all` is the address portion, not the direction.

### OPTIONS

`OPTIONS` are optional. However, if multiple options are specified, they must be in the order shown here.

* `log`: When the specified action is performed, the contents of the packet header will be written to the ipl(4) packet logging pseudo-device.
* `quick`: If a packet matches this rule, the specified action is performed and no further rules are processed.
* `on`: Must be followed by an interface name, as displayed by ifconfig(8). The rule only matches when the packet passes through the specified interface in the specified direction.

When using the `log` keyword, the following modifiers can be used in order:

* `body`: Indicates that the first 128 bytes of the packet content will be logged after the header.
* `first`: If the `log` keyword is used with the `keep state` option, it is recommended to use this option so that only the triggering packet is logged, rather than every matching stateful connection packet.

Additional options can also be used to specify error return messages.

### PROTO\_TYPE

`PROTO_TYPE` is optional. However, if the rule needs to specify `SRC_PORT` or `DST_PORT`, it is required because it defines the protocol type. When specifying the protocol type, use the `proto` keyword followed by the protocol number or protocol name from **/etc/protocols**. Example protocol names include `tcp`, `udp`, or `icmp`. If `PROTO_TYPE` is specified but `SRC_PORT` or `DST_PORT` is not, the rule will match all port numbers for that protocol.

### SRC\_ADDR

The `from` keyword is required and must be followed by a keyword representing the packet's source. The source address can be a hostname, an IP address with a CIDR mask, an address pool, or the `all` keyword.

IP address ranges that are not expressed in dotted decimal/mask length notation cannot be matched. The net-mgmt/ipcalc package and port can be used to simplify CIDR mask calculations. More information can be found on the tool's webpage: <http://jodies.de/ipcalc>.

### SRC\_PORT

The `SRC_PORT` keyword is optional. However, if this option is used, `PROTO_TYPE` must be defined first. The port number must be prefixed with the `port` keyword.

Multiple comparison operators are supported: `=` (equal to), `!=` (not equal to), `<` (less than), `>` (greater than), `<=` (less than or equal to), and `>=` (greater than or equal to).

When specifying a port range, two port numbers must be placed between `<>` (less than x or greater than y), `><` (greater than x and less than y), or `:` (greater than or equal to, and less than or equal to).

### DST\_ADDR

The `to` keyword is required and must be followed by a keyword representing the packet's destination. Similar to `SRC_ADDR`, it can be a hostname, an IP address with a CIDR mask, an address pool, or the `all` keyword.

### DST\_PORT

Similar to `SRC_PORT`, `DST_PORT` is optional. However, if this option is used, `PROTO_TYPE` must be defined first. The port number must also be prefixed with the `port` keyword.

### TCP\_FLAG|ICMP\_TYPE

If `tcp` is specified as `PROTO_TYPE`, flags can be specified using letters representing TCP connection states:

| Letter | TCP Flag |
| ------ | -------- |
| `S`    | SYN      |
| `A`    | ACK      |
| `P`    | PSH      |
| `F`    | FIN      |
| `U`    | URG      |
| `R`    | RST      |
| `C`    | CWR      |
| `E`    | ECE      |

If `icmp` is specified as `PROTO_TYPE`, the ICMP type to match can be specified.

### STATE

If a `pass` rule includes `keep state`, IPF will add an entry to its dynamic state table and allow subsequent packets matching that connection. IPF can track the state of TCP, UDP, and ICMP sessions. Any packet that IPF determines belongs to an already activated session, even if it belongs to a different protocol, will be allowed.

In IPF, when a packet passes through the interface connected to the public Internet, it is first checked against the dynamic state table. If the packet matches the next expected packet constituting an active session, it passes through the firewall and the session's state is updated. Packets that do not belong to an existing active session are matched against the outbound rule set. Packets arriving from the interface connected to the public Internet are similarly checked against the dynamic state table first. If the packet matches the next expected packet constituting an active session, it passes through the firewall and the session's state is updated. Packets that do not belong to an existing active session are matched against the inbound rule set.

Several keywords can be added after `keep state`. If used, these keywords set various options that control stateful filtering, such as setting connection limits or connection duration.

## Example Rule Set

This section demonstrates creating an example rule set that only allows services matching `pass` rules and blocks all other services.

FreeBSD uses the loopback interface (**lo0**) and IP address `127.0.0.1` for internal communication. The firewall rule set must include rules that allow these internally used packets to pass freely:

```sh
# Allow all traffic on the loopback interface
pass in quick on lo0 all
pass out quick on lo0 all
```

The public interface connected to the Internet is used to authorize and control all outbound and inbound connections. If one or more interfaces connect to private networks, those internal interfaces may need rules to allow packets originating from the LAN to travel between internal networks or to the interface connected to the Internet. The rule set should be divided into three main sections: any trusted internal interfaces, outbound connections through the public interface, and inbound connections through the public interface.

These two rules allow all traffic through the trusted LAN interface **em1**:

```ini
# Allow all traffic through the internal LAN interface (for private network)
pass out quick on em1 all
pass in quick on em1 all
```

The outbound and inbound sections for the public interface should place the most frequently matching rules first and the less frequently matching rules last, with the final rule blocking and logging all packets on that interface and direction.

The following rule set defines the outbound section for the public interface **em0**. These rules maintain state and identify the specific services that internal systems are authorized to access on the public Internet. All rules use `quick` and specify the appropriate port numbers, and destination addresses where applicable.

```ini
# Internet-facing interface (outbound)
# Match session requests from the internal network to the Internet

# Allow access to public DNS servers
# Replace x.x.x.x with the addresses listed in /etc/resolv.conf
# Repeat this rule for each DNS server
pass out quick on em0 proto tcp from any to x.x.x.x port = 53 flags S keep state
pass out quick on em0 proto udp from any to x.x.x.x port = 53 keep state

# Allow access to ISP's DHCP server, suitable for broadband connections such as cable modem or ADSL
# By default, use a generic rule with logging; after confirming the DHCP server address,
# fill in z.z.z.z in the next rule and enable it, while commenting out the current generic rule
pass out log quick on em0 proto udp from any to any port = 67 keep state
#pass out quick on em0 proto udp from any to z.z.z.z port = 67 keep state

# Allow outbound HTTP and HTTPS
pass out quick on em0 proto tcp from any to any port = 80 flags S keep state
pass out quick on em0 proto tcp from any to any port = 443 flags S keep state

# Allow outbound SMTP mail submission
pass out quick on em0 proto tcp from any to any port = 587 flags S keep state

# Allow outbound NTP time synchronization
pass out quick on em0 proto udp from any to any port = 123 keep state

# Allow outbound SSH
pass out quick on em0 proto tcp from any to any port = 22 flags S keep state

# Allow outbound ICMP echo request (ping)
pass out quick on em0 proto icmp from any to any icmp-type 8 keep state

# Block and log all other outbound traffic (log first occurrence only)
block out log first quick on em0 all
```

This example shows the rule set for the inbound section of the public interface, which first blocks all unwanted packets. This reduces the number of packets logged by the last rule.

```ini
# Internet-facing interface (inbound)
# Block all inbound traffic from non-routable or reserved address space
block in quick on em0 from 192.168.0.0/16 to any    # RFC 1918 private address
block in quick on em0 from 172.16.0.0/12 to any     # RFC 1918 private address
block in quick on em0 from 10.0.0.0/8 to any        # RFC 1918 private address
block in quick on em0 from 127.0.0.0/8 to any       # Loopback address
block in quick on em0 from 0.0.0.0/8 to any         # This network address
block in quick on em0 from 169.254.0.0/16 to any    # Link-local address (APIPA)
block in quick on em0 from 192.0.2.0/24 to any      # Documentation example reserved address
block in quick on em0 from 224.0.0.0/3 to any       # Class D multicast and Class E reserved

# Block fragmented and short TCP packets
block in quick on em0 all with frag
block in quick on em0 proto tcp all with short

# Block source-routed packets
block in quick on em0 all with opt lsrr
block in quick on em0 all with opt ssrr

# Block OS fingerprint probes, log first occurrence only
block in log first quick on em0 proto tcp from any to any flags FUP

# Block packets with special IP options
block in quick on em0 all with ipopts

# Block ICMP echo requests from outside (prevent external ping to this host)
block in quick on em0 proto icmp all icmp-type 8

# Block inbound access to NetBIOS/SMB related ports, log first occurrence only
block in log first quick on em0 proto tcp/udp from any to any port = 137
block in log first quick on em0 proto tcp/udp from any to any port = 138
block in log first quick on em0 proto tcp/udp from any to any port = 139
block in log first quick on em0 proto tcp from any to any port = 445
```

Whenever a rule using the `log first` option generates a log message, run `ipfstat -hio` to evaluate how many times the rule has been matched. A large number of matches may indicate that the system is under attack.

The remaining rules in the inbound section define which connections can be initiated from the Internet. The last rule denies all connections not explicitly allowed by preceding rules.

```ini
# Allow inbound traffic from ISP DHCP server; replace z.z.z.z with the same address used in the outbound rules
pass in quick on em0 proto udp from z.z.z.z to any port = 68 keep state

# Allow public HTTP connections to the specified internal web server
pass in quick on em0 proto tcp from any to x.x.x.x port = 80 flags S keep state

# Block and log all other inbound traffic (log first occurrence only)
block in log first quick on em0 all
```

## Configuring NAT

To enable NAT, add the following entries to **/etc/rc.conf** and specify the file name containing the NAT rules:

```ini
gateway_enable="YES"
ipnat_enable="YES"
ipnat_rules="/etc/ipnat.rules"
```

NAT rules are quite flexible and can implement various functions to meet the needs of both commercial and home users. The rule syntax shown here has been simplified to demonstrate common usage patterns.

The basic syntax for NAT rules is as follows, where `map` begins the rule and *IF* should be replaced with the name of the external interface:

```sh
# Syntax: map external_interface internal_IP_range -> public_address
map IF LAN_IP_RANGE -> PUBLIC_ADDRESS
```

*LAN\_IP\_RANGE* is the IP address range used by internal clients, typically a private address range such as `192.168.1.0/24`. *PUBLIC\_ADDRESS* can be a static external IP address or the keyword `0/32`, which represents the IP address assigned to *IF*.

In IPF, when a packet from the LAN reaches the firewall destined for a public address, it first passes through the outbound rules of the firewall rule set. Then, the packet is passed to the NAT rule set, which is read from top to bottom, and the first matching rule takes effect. IPF tests each NAT rule based on the packet's interface name and source IP address. When the packet's interface name matches the NAT rule, the packet's source IP address (located in the private LAN) is matched against the IP address range specified in *LAN\_IP\_RANGE*. After a match, the packet's source IP address is rewritten to the public IP address specified in *PUBLIC\_ADDRESS*. IPF records an entry in its internal NAT table so that when the packet returns from the Internet, it can be mapped back to the original private IP address, and the packet is then passed to the firewall rules for further processing.

For networks with a large number of internal systems or multiple subnets, translating each private IP address to a single public IP address can become a resource bottleneck. Two methods can be used to address this problem.

The first method is to allocate a port range for source ports. By adding the `portmap` keyword, NAT will only use source ports within the specified range:

```sh
# Map 192.168.1.0/24 addresses to the external interface, and limit TCP/UDP source port range
map em0 192.168.1.0/24 -> 0/32 portmap tcp/udp 20000:60000
```

Additionally, the `auto` keyword can be used to let NAT determine available ports automatically:

```sh
# Use auto to let the system automatically allocate source ports
map em0 192.168.1.0/24 -> 0/32 portmap tcp/udp auto
```

The second method is to use a public address pool. This method is particularly useful when there are too many LAN addresses to fit behind a single public address. If a block of public IP addresses is available, these public IP addresses can be used as an IP address pool for NAT selection, implementing address mapping when packets are sent outbound.

The public IP address range can be specified using a subnet mask or CIDR notation. The following two rules are equivalent:

```sh
# Specify public address pool using subnet mask format
map em0 192.168.1.0/24 -> 204.134.75.0/255.255.255.0
# Specify public address pool using CIDR notation (equivalent to the previous rule)
map em0 192.168.1.0/24 -> 204.134.75.0/24
```

A common practice is to isolate a publicly accessible web server or mail server to an internal network segment. Traffic for these servers still needs to pass through NAT, but inbound traffic needs to be redirected to the correct server through port redirection. For example, to map a web server with internal address `10.0.10.25` to its public IP address `20.20.20.5`, the following rule can be used:

```sh
# Redirect port 80 traffic destined for 20.20.20.5 to internal web server 10.0.10.25
rdr em0 20.20.20.5/32 port 80 -> 10.0.10.25 port 80
```

If this is the only web server, this rule also works because it redirects all external HTTP requests to `10.0.10.25`:

```sh
# Redirect all traffic destined for port 80 on the external interface to the internal server
rdr em0 0.0.0.0/0 port 80 -> 10.0.10.25 port 80
```

IPF includes a built-in FTP proxy that works with NAT. It monitors all outbound traffic for active or passive FTP connection requests and dynamically creates temporary filter rules containing the port numbers used by the FTP data channel. This eliminates the need to open a large number of high ports for FTP connections.

> **Note**
>
> The FTP protocol has gradually been replaced by secure alternatives such as SFTP and SCP. FTP usage scenarios in modern networks have significantly decreased, and the following FTP proxy configuration is only applicable to legacy environments that still need to support FTP.

In this example, the first rule invokes the proxy for outbound FTP traffic from the internal LAN. The second rule passes FTP traffic from the firewall to the Internet, and the third rule handles all non-FTP traffic:

```sh
# Enable FTP proxy for outbound FTP traffic from internal 10.0.10.0/29
map em0 10.0.10.0/29 -> 0/32 proxy port 21 ftp/tcp
# Enable FTP proxy for outbound FTP traffic from all other source addresses
map em0 0.0.0.0/0 -> 0/32 proxy port 21 ftp/tcp
# Perform regular NAT for the remaining non-FTP traffic from this network segment
map em0 10.0.10.0/29 -> 0/32
```

The FTP `map` rules should be placed before the NAT rules, so that when a packet matches an FTP rule, the FTP proxy creates temporary filter rules that allow FTP session packets to pass through and undergo NAT. All non-FTP LAN packets will not match the FTP rules, but if they match the third rule, they will undergo NAT.

Without the FTP proxy, the following firewall rules are needed. Note that without the proxy, all ports above `1024` must be allowed:

```ini
# Allow outbound FTP control connections from LAN clients (required for both active and passive modes)
pass out quick on em0 proto tcp from any to any port = 21 flags S keep state

# Allow outbound high data ports for passive mode FTP
pass out quick on em0 proto tcp from any to any port > 1024 flags S keep state

# Allow active mode FTP server callback to local data channel (port 20)
pass in quick on em0 proto tcp from any to any port = 20 flags S keep state
```

Each time the file containing NAT rules is edited, running `ipnat` requires the `-CF` option to delete current NAT rules and flush the dynamic translation table contents, along with `-f` to specify the NAT rule file name to load:

```sh
# ipnat -CF -f /etc/ipnat.rules
```

To display NAT statistics:

```sh
# ipnat -s
```

To list the current mappings in the NAT table:

```sh
# ipnat -l
```

To enable verbose mode and display information related to rule processing, active rules, and table entries:

```sh
# ipnat -v
```

## Viewing IPF Statistics

IPF includes the ipfstat(8) command, which can be used to retrieve and display statistics collected as packets match rules while passing through the firewall. Statistics accumulate since the firewall was last started or since they were last reset to zero via `ipf -Z`.

The default `ipfstat` output is shown below:

```sh
input packets: blocked 99286 passed 1255609 nomatch 14686 counted 0
 output packets: blocked 4200 passed 1284345 nomatch 14687 counted 0
 input packets logged: blocked 99286 passed 0
 output packets logged: blocked 0 passed 0
 packets logged: input 0 output 0
 log failures: input 3898 output 0
 fragment state(in): kept 0 lost 0
 fragment state(out): kept 0 lost 0
 packet state(in): kept 169364 lost 0
 packet state(out): kept 431395 lost 0
 ICMP replies: 0 TCP RSTs sent: 0
 Result cache hits(in): 1215208 (out): 1098963
 IN Pullups succeeded: 2 failed: 0
 OUT Pullups succeeded: 0 failed: 0
 Fastroute successes: 0 failures: 0
 TCP cksum fails(in): 0 (out): 0
 Packet log flags set: (0)
```

This command provides multiple options. When using `-i` for inbound or `-o` for outbound, the command retrieves and displays the corresponding list of filtering rules currently installed and used by the kernel. To also view rule numbers, add `-n`. For example, `ipfstat -on` displays the outbound rule table with rule numbers:

```sh
@1 pass out on em1 from any to any
@2 block out on em0 from any to any
@3 pass out quick on em0 proto tcp/udp from any to any keep state
```

Adding `-h` prepends each rule with the number of times it has been matched. For example, `ipfstat -oh` displays the outbound internal rule table with the usage count before each rule:

```sh
2451423 pass out on em1 from any to any
354727 block out on em0 from any to any
430918 pass out quick on em0 proto tcp/udp from any to any keep state
```

To display the state table in a format similar to top(1), use `ipfstat -t`. This option is useful for identifying and viewing attack packets when the firewall is under attack. Optional sub-flags can be used for real-time monitoring of destination or source IP, port, or protocol.

## IPF Logging

IPF provides `ipmon`, which can be used to log firewall information in a readable format. It requires adding `options IPFILTER_LOG` to a custom kernel first, following the instructions for configuring the FreeBSD kernel.

This command typically runs in daemon mode to provide a continuous system log file for viewing historical events. Since FreeBSD includes the syslogd(8) system, which automatically rotates system logs, the default **rc.conf** `ipmon_flags` statement uses `-Ds`:

```sh
ipmon_flags="-Ds" # D = Start in daemon mode
                  # s = Log to syslog
                  # v = Log TCP window, ack, seq
                  # n = Map IP addresses and ports to names
```

Logging can be used to review information after the fact, such as which packets were dropped, where they came from, and their destinations. This information is very useful for tracking attackers.

After enabling logging in **rc.conf** and starting it with `service ipmon start`, IPF only logs rules that contain the `log` keyword. The firewall administrator decides which rules in the rule set should be logged, and typically only deny rules are logged. By convention, the `log` keyword is included in the last rule of the rule set to view all packets that did not match any rule.

By default, `ipmon -Ds` mode uses `local0` as the logging facility. The following log levels can be used to further differentiate the recorded data:

```sh
LOG_INFO - Packets logged with the "log" keyword, as an action rather than pass or block.
LOG_NOTICE - Packets that are logged and also passed
LOG_WARNING - Packets that are logged and also blocked
LOG_ERR - Packets that are logged and considered short due to incomplete headers
```

To log all IPF messages to **/var/log/ipfilter.log**, first create an empty file:

```sh
# touch /var/log/ipfilter.log
```

Then, to write all logged messages to the specified file, add the following entry to **/etc/syslog.conf**:

```sh
local0.* /var/log/ipfilter.log
```

To apply the changes and have syslogd(8) read the modified **/etc/syslog.conf**, run `service syslogd reload`.

You also need to edit **/etc/newsyslog.conf** to rotate the new log file.

Messages generated by `ipmon` consist of space-separated data fields. The common fields for all messages are as follows:

| Field     | Description                                                                                                                                                         |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Date      | The date the packet was received.                                                                                                                                   |
| Time      | Format HH:MM:SS.F, representing hours, minutes, seconds, and fractional seconds.                                                                                    |
| Interface | The name of the interface that processed the packet.                                                                                                                |
| Rule      | The rule group and rule number, in the format `@0:17`.                                                                                                              |
| Action    | `p` for pass, `b` for block, `S` for short packet, `n` for no rule match, `L` for log rule.                                                                         |
| Addresses | Source address and port separated by a comma, followed by the → symbol, then the destination address and port. For example: `209.53.17.22,80 → 198.73.220.17,1722`. |
| Protocol  | `PR` followed by the protocol name or number. For example: `PR tcp`.                                                                                                |
| Length    | `len` followed by the header length and total length of the packet. For example: `len 20 40`.                                                                       |

If the packet is a TCP packet, there is an additional field prefixed with a hyphen, followed by letters corresponding to the set flags. For a list of letters and flags, refer to ipf(5).

If the packet is an ICMP packet, there are two fields at the end of the message: the first is always "icmp" and the second is the ICMP message and sub-message type separated by a slash. For example: `icmp 3/3` indicates a port unreachable message.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://book.bsdcn.org/ask/flat/chapter-31-firewalls/di-31.3-jie-ipfilter-ipf.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
