LIBNIDS(3)
π NAME π
okay bestie, this is libnids β from the LIBNIDS(3) Library Functions Manual β aka the network intrusion detection system E-box library. It's giving packet-reassembly royalty, no cap. π
β¨ SYNOPSIS β¨
Here's the lineup, bestie. Copy these literally β no vibes-based renaming:
#include <nids.h>
extern struct nids_prm nids_params;
extern char nids_errbuf[];
int
nids_init(void);
void
nids_register_ip_frag(void (*ip_frag_func)(struct ip *pkt, int len));
void
nids_unregister_ip_frag(void (*ip_frag_func)(struct ip *pkt, int len));
void
nids_register_ip(void (*ip_func)(struct ip *pkt, int len));
void
nids_unregister_ip(void (*ip_func)(struct ip *pkt, int len));
void
nids_register_udp(void (*udp_func)(struct tuple4 *addr, u_char *data, int len, struct ip *pkt));
void
nids_unregister_udp(void (*udp_func)(struct tuple4 *addr, u_char *data, int len, struct ip *pkt));
void
nids_register_tcp(void (*tcp_func)(struct tcp_stream *ts, void **param));
void
nids_unregister_tcp(void (*tcp_func)(struct tcp_stream *ts, void **param));
void
nids_killtcp(struct tcp_stream *ts);
void
nids_discard(struct tcp_stream *ts, int numbytes);
void
nids_run(void);
int
nids_dispatch(int cnt);
int
nids_next(void);
int
nids_getfd(void);
int
nids_register_chksum_ctl(struct nids_chksum_ctl *, int);
void
nids_pcap_handler(u_char *par, struct pcap_pkthdr *hdr, u_char *data);
struct tcp_stream *
nids_find_tcp_stream(struct tuple4 *addr);
πΈ DESCRIPTION πΈ
libnids gives you the functionality of a network intrusion detection system (NIDS) E-box component. Right now it performs:
- IP defragmentation
- TCP stream reassembly
- TCP port scan detection
And the flex? It performs TCP/IP reassembly in exactly the same way as Linux 2.0.36 kernels, and correctly handles all of the attacks implemented in fragrouter(8) (plus many other attacks as well). Periodt. π₯
π ROUTINES π
nids_init() initializes the application for sniffing, based on the values set in the global variable nids_params, declared as follows:
struct nids_prm {
int n_tcp_streams;
int n_hosts;
char *device;
char *filename;
int sk_buff_size;
int dev_addon;
void (*syslog)(int type, int err, struct ip *iph, void *data);
int syslog_level;
int scan_num_hosts;
int scan_num_ports;
int scan_delay;
void (*no_mem)(void);
int (*ip_filter)(struct ip *iph);
char *pcap_filter;
int promisc;
int one_loop_less;
int pcap_timeout;
int multiproc;
int queue_limit;
int tcp_workarounds;
pcap_t *pcap_desc;
} nids_params;
The members of this structure are:
n_tcp_streamsβ Size of the hash table used for storing TCP connection information (a maximum of3/4 * n_tcp_streamsTCP connections will be followed simultaneously). Default value:1024.n_hostsβ Size of the hash table used for storing IP defragmentation information. Default value:256.filenameβ If this variable is set,libnidswill callpcap_open_offlinewith this variable as the argument (instead ofpcap_open_live()). Default value:NULL.deviceβ Interface to monitor. Default value:NULL(in which case an appropriate device is determined automatically). If this variable is assigned valueall,libnidswill attempt to capture packets on all interfaces (which works on Linux only).sk_buff_sizeβ Size ofstruct sk_buff(used for queuing packets), which should be set to match the value on the hosts being monitored. Default value:168.dev_addonβ Number of bytes instruct sk_buffreserved for link-layer information. Default value:-1(in which case an appropriate offset is determined automatically based on link-layer type).syslogβ Syslog callback function, used to report unusual conditions, such as port scan attempts, invalid TCP header flags, etc. Default value:nids_syslog(which logs messages viasyslog(3)without regard for message rate per second or free disk space).syslog_levelβ Log level used bynids_syslogfor reporting events viasyslog(3). Default value:LOG_ALERT.scan_num_hostsβ Size of hash table used for storing portscan information (the maximum number portscans that will be detected simultaneously). If set to0, portscan detection will be disabled. Default value:256.scan_num_portsβ Minimum number of ports that must be scanned from the same source host before it is identified as a portscan. Default value:10.scan_delayβ Maximum delay (in milliseconds) between connections to different ports for them to be identified as part of a portscan. Default value:3000.no_memβ Out-of-memory callback function, used to terminate the calling process gracefully.ip_filterβ IP filtering callback function, used to selectively discard IP packets, inspected after reassembly. If the function returns a non-zero value, the packet is processed; otherwise, it is discarded. Default value:nids_ip_filter(which always returns1).pcap_filterβpcap(3)filter string applied to the link-layer (raw, unassembled) packets. Note: filters liketcp dst port 23will NOT correctly handle appropriately fragmented traffic, e.g. 8-byte IP fragments; one should add"or (ip[6:2] & 0x1fff != 0)"at the end of the filter to process reassembled packets. Default value:NULL.promiscβ If non-zero,libnidswill set the interface(s) it listens on to promiscuous mode. Default value:1.one_loop_lessβ Disabled by default; see comments inAPI.htmlfile.pcap_timeoutβ Sets the pcap read timeout, which may or may not be supported by your platform. Default value:1024.multiprocβ If nonzero, creates a separate thread for packets processing. SeeAPI.html. Default value:0.queue_limitβ Ifmultiprocis nonzero, this is the maximum number of packets queued in the thread which reads packets from libpcap. Default value:20000.tcp_workaroundsβ Enables extra checks for faulty implementations of TCP such as the ones which allow connections to be closed despite the fact that there should be retransmissions for lost packets first (as stated by RFC 793, section 3.5). If non-zero,libnidswill set theNIDS_TIMED_OUTstate for savagely closed connections. Default value:0.pcap_descβ If this variable is set,libnidswill call neitherpcap_open_livenorpcap_open_offline, but will use a pre-opened PCAP descriptor; use this withnids_pcap_handler()in order to interactively feed packets tolibnids. Default value:NULL.
Returns 1 on success, 0 on failure (in which case nids_errbuf contains an appropriate error message).
nids_register_ip_frag() registers a user-defined callback function to process all incoming IP packets (including IP fragments, packets with invalid checksums, etc.).
nids_unregister_ip_frag() unregisters a user-defined callback function to process all incoming IP packets.
nids_register_ip() registers a user-defined callback function to process IP packets validated and reassembled by libnids.
nids_unregister_ip() unregisters a user-defined callback function to process IP packets.
nids_register_udp() registers a user-defined callback function to process UDP packets validated and reassembled by libnids.
nids_unregister_udp() unregisters a user-defined callback function to process UDP packets.
nids_register_tcp() registers a user-defined callback function to process TCP streams validated and reassembled by libnids. The tcp_stream structure is defined as follows:
struct tcp_stream {
struct tuple4 {
u_short source;
u_short dest;
u_int saddr;
u_int daddr;
} addr;
char nids_state;
struct half_stream {
char state;
char collect;
char collect_urg;
char *data;
u_char urgdata;
int count;
int offset;
int count_new;
char count_new_urg;
...
} client;
struct half_stream server;
...
void *user;
};
The members of the tuple4 structure identify a unique TCP connection:
source,destβ Client and server port numbers.saddr,daddrβ Client and server IP addresses.
The members of the half_stream structure describe each half of a TCP connection (client and server):
stateβ Socket state (e.g.TCP_ESTABLISHED).collectβ A boolean which specifies whether to collect data for this half of the connection in thedatabuffer.collect_urgβ A boolean which specifies whether to collect urgent data pointed to by the TCP urgent pointer for this half of the connection in theurgdatabuffer.dataβ Buffer for normal data.urgdataβ One-byte buffer for urgent data.countβ The number of bytes appended todatasince the creation of the connection.offsetβ The current offset from the first byte stored in thedatabuffer, identifying the start of newly received data.count_newβ The number of bytes appended todatasince the last invocation of the TCP callback function (if0, no new data arrived).count_new_urgβ The number of bytes appended tourgdatasince the last invocation of the TCP callback function (if0, no new urgent data arrived).
The value of the nids_state field provides information about the state of the TCP connection, to be used by the TCP callback function:
NIDS_JUST_ESTβ Connection just established. Connection parameters in theaddrstructure are available for inspection. If the connection is interesting, the TCP callback function may specify which data it wishes to receive in the future by setting non-zero values for thecollectorcollect_urgvariables in the appropriateclientorserverhalf_streamstructure members.NIDS_DATAβ New data has arrived on a connection. Thehalf_streamstructures contain buffers of data.NIDS_CLOSE,NIDS_RESET,NIDS_TIMED_OUTβ Connection has closed. The TCP callback function should free any resources it may have allocated for this connection.
okay so real talk about that param pointer β when libnids hands it to your TCP callback function, you can set it to stash a pointer to your own connection-specific data, so the next time that same TCP callback fires you get your stuff back (think: the current working directory for an FTP control connection, that kind of thing π
).
And the user pointer inside the tcp_stream structure? Same idea, except it's global to the stream, bestie. The param pointer is different from one callback function to the next, even when both of them got called for the exact same stream. Subtle but iconic. π¦
nids_unregister_tcp()β unregisters a user-defined callback function that was processing TCP streams. Bye bestie πnids_killtcp()β tears down the TCP connection you point it at with symmetric RST packets between client and server. It's giving "we're done here" energy. π₯nids_discard()β call this from inside the TCP callback function to say how many bytes to discard from the beginning of the data buffer (it updates theoffsetvalue to match) once the callback function exits. If you don't call it, all the new data β the wholecount_newbytes β gets discarded by default. So like. Speak now or lose the data fr. πnids_run()β kicks off your packet-driven application: reads packets in an endless loop and invokes the registered callback functions to handle new data as it arrives. Heads up though: this function does not return. Ever. It's a forever vibe. πnids_dispatch()β tries to processcntpackets before returning. Passcntof-1and it means all packets available in one pcap buffer, or all packets in a file when you're reading offline. On success you get back the count of packets processed β which can legitimately be zero, like at EOF on an offline read, or when you hitpcap_timeout(if your platform supports that). On failure it returns-1and drops an appropriate error message intonids_errbuf. πΈnids_next()β processes the next available packet before returning. Returns1on success,0if no packet was processed β and it setsnids_effbufappropriately if an error stopped the packet from being processed. β¨nids_getfd()β for when your application is sleeping inselect(2)and wants to snoop for a socket file descriptor sitting in the readfd_set. Returns the file descriptor on success,-1on failure, and in that failure casenids_errbufhas an appropriate error message for you. π«Άnids_register_chksum_ctl()β takes an array ofstruct nids_chksum_ctlelements plus the number of elements in that array. And anids_chksum_ctlelement looks exactly like this, no cap:
struct nids_chksum_ctl {
u_int netaddr;
u_int mask;
u_int action;
/* private members */
};
So here's the tea on how that array gets used β β the internal checksumming functions go through the elements one by one, and if the source ip SRCIP of the current packet satisfies the condition
(SRCIP&chksum_ctl_array[i].mask)==chksum_ctl_array[i].netaddr
then: if the action field is NIDS_DO_CHKSUM, that packet will be checksummed; if the action field is NIDS_DONT_CHKSUM, that packet will not be checksummed. And if the packet matches none of the array elements at all? The default action is to perform checksumming. Periodt. π
nids_pcap_handler()β for the girlies already running a capture with libpcap: use this to pass frames to libnids interactively (frame per frame) instead of making libnids do the capturing itself. Main character energy, you keep the wheel. πnids_find_tcp_stream()β returns a pointer to thetcp_streamstructure corresponding to the tuple you passed as the argument, if libnids already knows about that TCP connection. Otherwise?NULL. Sorry babe. πnids_free_tcp_stream()β removes the giventcp_streamfrom the list of streams that libnids is tracking.
β οΈ Warning bestie, for real: usingnids_free_tcp_stream()can result in crashes! See the comments in theAPI.htmlfile before you go there. π
β¨ SEE ALSO β¨
The squad, assembled. π
πΈ AUTHOR πΈ
Rafal Wojtczuk <nergal@icm.edu.pl>
Manpage by Dug Song <dugsong@monkey.org>, minor updates by Michael Pomraning <mjp@pilcrow.madison.wi.us>
That's the whole LIBNIDS(3) page, start to finish β go build something unhinged with it, bestie ππ¦β¨ (signing off from the LIBNIDS(3) manpage, footer and all π«Ά)
π¦ where this page comes from
- alpine 3.24: libnids-doc 1.26-r2 Β· GPL-2.0-only
- arch rolling: libnids 1.26-6 Β· GPL-2.0-only
- epel 9: libnids-devel 1.24-23.el9 Β· GPLv2+
- fedora 43: libnids-devel 1.24-34.fc43 Β· GPL-2.0-or-later
- fedora 43: libnids-devel 1.24-34.fc43 Β· GPL-2.0-or-later
- fedora 44: libnids-devel 1.24-35.fc44 Β· GPL-2.0-or-later
- fedora 44: libnids-devel 1.24-35.fc44 Β· GPL-2.0-or-later
- nixos 26.05: libnids 1.24
- nixpkgs unstable: libnids 1.24
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms