Userspace programming topics.
IPFIREwall is made up of two communicating parts: the first runs
as a common application in user space, and the second, the real firewall, runs
in the separate world of the operating system, the kernel.
The two modules communicate by means of an interface called netlink sockets,
which provides functions similar to those involving network socket communication.
The userspace IPFIREWALL program is the one which presents an interactive
interface for the user. A short list of userspace programming topics follows. It is not intended
to be exhaustive, since source code is well commented. The reader can have a look at
the code and email to me for explanations.
Topics.
- Program structure.
- IPFIRE-wall userspace program is made up of two processes always running.
The first is the main loop that provides an interface for receiving commands from
the user and sending them to the kernel (e.g. adding a rule) or simply providing a
local feedback (e.g. showing local statistics). The second is a son
process that listens on the netlink socket to receive packet information
from the kernel firewall and prints such information on the console.
A fork() in the main process creates the son. Each one has got a netlink
socket. They are separate because of the different meaning of the two flows, and for program
managing reasons.
A third son process can be started if the user wants the DNS resolver in function: at determined intervals it wakes up and updates the list of blocked sites. See interface.c in userspace source directory. - Signals.
- signal.h library is used to raise and deliver signals from a process to the others.
For instance, in interface.c, in main program we can see:
signal(SIGUSR1, sig1_handler);
SIGUSR1 is used to tell the son process that there's a message on the pipe (see below). .
signal(SIGSEGV, signal_handler);
signal(SIGINT, son_signal_handler);
signal(SIGHUP, son_signal_handler);
signal(SIGTERM, son_signal_handler);
- Pipes.
- As interprocess communication, in addition to the simple signal interface, pipes are used to exchange messages between processes.
- Network structures.
- Userspace program has to know everything about network packet headers, just as in kernel side.
- g_getcharlib.c.
- Userspace program makes use of the library g_getcharlib, written by myself
to support unbuffered I/O on the terminal device and the capture of all keys from keyboard.
If you notice, function keys as well as control keys are available to IPFIRE.
This library is available also as a separate package here and was written to support a large use of special keys in calendar program. Library uses ioctl interface in conjunction with timers to catch special keys. - Netlink library. (libnetl.c)
- Netlink library accomplishes userspace/kernelspace communication.
In libnetl.c a public interface is built over a low level private one, to assure a simple use and an adequate error reporting. You should have a look at libnetl.c, it is wide commented.
An excerpt from libnetl.h is reported, to represent the public interface for programming.#define NETLINK_IPFI_DATA 17 #define NETLINK_IPFI_CONTROL 18 struct netl_handle { int fd; struct sockaddr_nl local; struct sockaddr_nl peer; }; /* allocates a netlink handle containing socket file descriptor * and netlink source and destination addresses */ /* protocol: NETLINK_IPFI_DATA or NETLINK_IPFI_CONTROL */ struct netl_handle *alloc_netl_handle (int protocol); /* free socket and mallocated memory for handle */ struct netl_handle* netl_free_handle(struct netl_handle *h); /* send a message to kernel */ int send_to_kern(const struct netl_handle *h, const void *msg, size_t len); /* read a message from kernel space */ int read_from_kern(const struct netl_handle *h, unsigned char *buf, size_t len); /* returns the string corresponding to the error code */ char* libnetl_err_string(void) ; /* prints the string s followed by libnetl errors and errno */ void libnetl_perror(const char *s); /* creation of the packet to send to kernel space */ /* allocates the netlink packet and fills in header fields */ struct nlmsghdr* alloc_and_fill_nlheader(int payload_size); /* copies data to send into payload */ void* fill_payload(struct nlmsghdr* nlhmess, const void* data, size_t len); /* frees nlmsghdr mallocated pointer */ struct nlmsghdr* netl_free_nlmess(struct nlmsghdr* nlmess);
- Other programmers interfaces.
- If anyone wants to build another interface (e.g. a GUI) over ipfirewall, must know that is quite easy if ipfire_userspace.c functions are used. interface_functions.c is an example of how to use generic ipfire functions in ipfire_userspace.c. The last contains a lot of utilities to manipulate network addresses and strings representing CIDR notations and not forms or intervals, as !192.168.1.100 or 192.168.0.0-192.168.0.100, or 192.168.0.0/24 or 192.168.0.0/255.255.255.0.