FreeBSD Netgraph, consider traffic
In the last review, we got acquainted with the ng_bridge, ng_ether and ng_ksocket modules and built an Ethernet tunnel over the Internet on their basis, and today I will tell you how to use the additional netgraph modules to calculate the traffic passing through this tunnel.
We will use the ng_netflow module to account for traffic.
Wikipedia tells
Netflow, a protocol developed by Cisco to collect information about IP traffic within a network.
Cisco routers generate a netflow stream, which is transmitted to a special node known as netflow collector.
Our ng_netflow pretends to be a cisco router and will send the real cisco netflow to the collector. The collector collects information, groups traffic by streams, IP addresses, draws graphs, etc. Depends on the implementation. I used the trial netflow analyzer 7.5.
Again about the cubes
We will need:

ng_netflow - The module of the kernel subsystem netgraph that implements the cisco netflow protocol version 5. Ng_netflow receives incoming traffic, identifies it, and creates counters of active traffic flows. Streams are disassembled by protocols, port numbers, ToS, interfaces. Completed streams are sent as UDP datagrams to the Netflow collector. The stream is considered complete: if an RST or TCP FIN packet was received. Also for flows, there are timeouts by which the stream will be completed and transferred to the collector. Active thread timeout - 1800 seconds by default. And the default timeout of an inactive stream is 15 seconds.
Ng_netflow hooks are named iface0, iface1, iface2, ifaceN. Also their corresponding out0, out1, out2, outN. And the export statistics export hook.
Incoming traffic in ifaceN is processed by the accounting module. If the corresponding outN hook is connected, the traffic goes into it without changes, if it is not connected, it does not go anywhere. Traffic included in the outN hook goes without changes to the ifaceN hook, without processing by the accounting module. That is, only incoming traffic in ifaceN actually gets to the counters. There are settings for controlling traffic accounting behavior, which will be described below. As a result, through the export hook, UDP netflow datagrams will be output, this kitchen is usually connected to the inet / dgram / udp hook of the ng_ksocket module.
The control messages received by the module are the same commands: info, ifinfo, setdlt, setifindex, settimeouts, setconfig, show. I will describe some, read the rest in man ng_netflow.
Setdlt sets the type of interface connected to ifaceN. Of all the possible options (/usr/src/sys/net/bpf.h) , only Ethernet and bare IP are supported, respectively options 1 and 12. The first option is set by default. The syntax is “setdlt {iface = 0 dlt = 12}” Settimeouts - sets the timeouts of active and inactive threads, after which statistics will be sent to the collector. The syntax is "settimeouts {inactive = 15 active = 1800}" ng_hub - the name comes from network terminology. Ethernet hubs have not been used anywhere for a long time and, unlike modern smart Ethernet switches, they could do only two simple actions: receive a packet on any interface, and send this packet to all interfaces.
/*
* Data-link level type codes.
*/
#define DLT_NULL 0 /* BSD loopback encapsulation */
#define DLT_EN10MB 1 /* Ethernet (10Mb) */
#define DLT_EN3MB 2 /* Experimental Ethernet (3Mb) */
#define DLT_AX25 3 /* Amateur Radio AX.25 */
#define DLT_PRONET 4 /* Proteon ProNET Token Ring */
#define DLT_CHAOS 5 /* Chaos */
#define DLT_IEEE802 6 /* IEEE 802 Networks */
#define DLT_ARCNET 7 /* ARCNET */
#define DLT_SLIP 8 /* Serial Line IP */
#define DLT_PPP 9 /* Point-to-point Protocol */
#define DLT_FDDI 10 /* FDDI */
#define DLT_ATM_RFC1483 11 /* LLC/SNAP encapsulated atm */
#define DLT_RAW 12 /* raw IP */

This module works in exactly the same way. It accepts data on any connected hook with an arbitrary name, and sends this data without changes to all connected hooks. Does not accept control messages.
We will not pass traffic through ng_netgraph through, using the outN hook, but use the ng_hub module to copy traffic passing through the tunnel in both directions.
We make a graph.

Compared to the old one , the changes in the new one are visible:
1. A new ng_hub module is inserted in the gap between link2 of the ng_bridge module and inet / dgram / udp of the ng_ksocket module.
2. A new ng_netflow is connected to ng_hub.
3. ng_netflow is connected to a new copy of the ng_ksocket module, which is connected to the netflow collector.
We collect the graph in the system.
On the bsd2 server side, you won’t have to make any changes.
On the bsd1 server we will collect everything from the beginning.
We create the ng_bridge node and connect to its hook “link0” the hook of the network interface “em1” “lower”.
ngctl mkpeer em1: bridge lower link0
We name the newly created node by the name “switch”, it can be found on the path “em1: lower”.
ngctl name em1: lower switch We
connect to the "link1" of our "switch" upper network interface "em1".
ngctl connect switch: em1: link1 upper
Create the ng_hub node and connect it to the hublink0 hook our
link2 hook ngctl mkpeer switch: hub link2 hublink0
We name the newly created node with the name hub, it can be found along the path " switch: link2 »
ngctl name switch: link2 hub
We create the ng_ksocket node and connect to its hook “inet / dgram / udp” “hublink1” of our “hub”
ngctl mkpeer hub: ksocket hublink1 inet / dgram / udp
We name the newly created node with the name “hub_socket”, it can be found on the path “hub : hublink1 "
ngctl name hub: hublink1 hub_socket
We create the ng_netflow node and connect to its hook" iface0 "" hublink2 "of our" hub "
ngctl mkpeer hub: netflow hublink2 iface0
We name the newly created node with the name" netflow ", it can be found on the path" hub: hublink2 "
ngctl name hub: hublink2 netflow
Create another ng_ksocket and connect to its hook" inet / dgram / udp "" export "created by" netflow "
ngctl mkpeer netflow: ksocket export inet / dgram / udp
We name the newly created node with the name "netflow_socket", it can be found on the path "netflow: export"
ngctl name netflow: export netflow_socket We
send the command "bind" to our "switch_socket", with parameters. ksocket will take port 7777 on IP 1.1.1.1.
ngctl msg switch_socket: bind inet / 1.1.1.1: 7777
Send the “connect” command to our “switch_socket”, with parameters. ksocket will connect to port 7777 at IP address 2.2.2.2.
ngctl msg switch_socket: connect inet / 2.2.2.2: 7777
Send the “connect” command to our “netflow_socket”, with parameters. ksocket will connect to port 9996 at IP address 3.3.3.3. There should live a netflow collector.
ngctl msg netflow_socket: connect inet / 3.3.3.3: 9996
We send a command to the ng_ether module of the em1 network interface to switch to the mode of wiretapping of packets addressed not to it. After all, we now need to receive packets for devices located in our virtual network.
ngctl msg em1: setpromisc 1
ngctl msg em1: setautosrc 0
The final graph assembly script: We look at the result: There are 8 total nodes: Having driven some traffic through the tunnel we look: Just by looking at the collector statistics, you can see the traffic that has passed through the tunnel.
#!/bin/sh
self=1.1.1.1
peer=2.2.2.2
collector=3.3.3.3:9996
port=7777
if=em1
case "$1" in
start)
echo "Starting netgraph switch."
ngctl mkpeer ${if}: bridge lower link0
ngctl name ${if}:lower switch
ngctl connect switch: ${if}: link1 upper
ngctl mkpeer switch: hub link2 hublink0
ngctl name switch:link2 hub
ngctl mkpeer hub: ksocket hublink1 inet/dgram/udp
ngctl name hub:hublink1 hub_socket
ngctl mkpeer hub: netflow hublink2 iface0
ngctl name hub:hublink2 netflow
ngctl mkpeer netflow: ksocket export inet/dgram/udp
ngctl name netflow:export netflow_socket
ngctl msg hub_socket: bind inet/${self}:${port}
ngctl msg hub_socket: connect inet/${peer}:${port}
ngctl msg netflow_socket: connect inet/${collector}
ngctl msg ${if}: setpromisc 1
ngctl msg ${if}: setautosrc 0
echo "Ok."
exit 0
;;
stop)
echo "Stopping netgraph switch."
ngctl shutdown netflow_socket:
ngctl shutdown netflow:
ngctl shutdown hub_socket:
ngctl shutdown hub:
ngctl shutdown switch:
ngctl shutdown ${if}:
echo "Ok."
exit 0
;;
restart)
sh $0 stop
sh $0 start
;;
*)
echo "Usage: `basename $0` { start | stop | restart }"
exit 64
;;
esac
[root@bsd1] /root/> ngctl list
Name: em0 Type: ether ID: 00000001 Num hooks: 0
Name: em1 Type: ether ID: 00000002 Num hooks: 2
Name: switch Type: bridge ID: 000002c7 Num hooks: 3
Name: ngctl56729 Type: socket ID: 000002e1 Num hooks: 0
Name: hub_socket Type: ksocket ID: 000002ce Num hooks: 1
Name: hub Type: hub ID: 000002cb Num hooks: 3
Name: netflow_socket Type: ksocket ID: 000002d4 Num hooks: 1
Name: netflow Type: netflow ID: 000002d1 Num hooks: 2
[root@bsd1] /root/> ngctl msg netflow: info
Rec'd response "info" (805306369) from "[2d1]:":
Args: { Bytes=1722435 Packets=13683 Records used=27 Active expiries=203 Inactive expiries=5566 Inactive timeout=15 Active timeout=1800 }

the end
The practical use of traffic accounting in the tunnel is doubtful, so the collection of such a graph can be considered as an example for further understanding of the subsystem and the modernization of ready-made schemes to fit your needs.
In the following articles I will describe the interaction of the netgraph subsystem with ipfw, with a more practical way of accounting for traffic through ng_netflow.
See you again.