---
name: "lsfcc"
section: "1"
platform: "linux"
package: "lsfcc"
version: "0.2"
release: "Debian 3.0 (Woody)"
platforms: ["linux"]
url: "https://new.carta.tech/lsfcc"
---

# lsfcc(1)

a Linux Socket Filter Command Compiler

## NAME

lsfcc - a Linux Socket Filter Command Compiler

## SYNOPSIS

**lsfcc** *\[-o \<output filename\>\] \<input files\>*

## DESCRIPTION

**lsfcc** is a compiler that will accept directives written in a simple C-like language to create a filter program that can be applied by either the Linux Socket Filter or the Berkeley Packet Filter.

## OPTIONS

**-o \<output filename\>** changes the filename of the created program from "lsf.out" to the supplied value.

## SYNTAX

There are a number of basic top-level constructs.

**packet**

This is used to teach lsfcc about new packet formats.

packet udp {

  u\_int16\_t	source;

  u\_int16\_t	dest;

  u\_int16\_t	len;

  u\_int16\_t	check;

};

The block begins with the keyword *packet* , followed by an arbitrary name for this packet, and then a brace delimited list of fields. Each field consists of a keyword describing the size of the field, followed by an arbitrary name for the field, followed by a semi-colon. There may optionally be a colon and a number  before the semi-colon, in which case that number is taken to be the width of the field in bits, and the original size keyword disregarded. Size keywords include (u\_)?int(8\|16\|32)\_t, (unsigned )?(char\|int\|long)  and various other things.

This syntax is stolen in a large part from C (and in fact *struct* may be used as an alias for *packet* ), and is intended to make it easy to use cut-and-pasting from C header files to build new declarations.

No, I'm not going to write a BNF grammar. Go and read the source.

**base**

This informs the compiler of the starting offset of a packet header. When the compiler sees a directive of the form **udp\[source\]** ,it loads the *source* field from a *udp* header structure assumed to be starting at offset 0 in the packet. This is not necessarily what you want. By specifying a *base* statement such as

base udp 0x1000;

the compiler will load all field references rooted at a udp header from an offset of 0x1000.

**fields**

This quite naturally brings us to the point of describing fields. Fields are referenced as a chain of headers, followed by either a field name or byte offset and length.

*udp\[source\]* refers to the source field in the udp header.

*ip.udp\[source\]* refers to the source field in a udp header immediately following an ip  header.

*foo.bar.bob\[12, 4\]* refers to the 4 bytes of data starting at a 12 byte offset into the payload of a packet consisting of a bob packet encapsulated in a bar packet encapsulated in a foo packet.

*ip\[2.1, 1.3\]* refers to the 11 bits (1 \* 8 + 3) of data at a bit offset of 17 (2 \* 8  + 1) into the payload of this ip packet.

And so on.

**directives**

And finally, directives. This should all be terribly familiar. There are three keywords, *accept, deny,* and *if.* *Accept* and *deny* do about what you would expect (stop examining the packet and either accept or deny it, in case you don't), and *if* is used in constructing conditional statements.

This is all stolen direct from C, so to save explanation, here's an example.

if((udp\[source\] \< 1024) && (udp\[dest\] \< 1024)) accept;

deny;

This will only allow packets between privileged ports.

## BUGS

Endianness is not handled in any way, shape or form.

Feature completeness isn't.

This manpage is terrible.

## SEE ALSO

**[bpf(4)](/bpf/4.md)**

## AUTHOR

This manual page was written by Mikolaj J. Habryn \<dichro-lsfcc@rcpt.to\>.
