├── .travis.yml ├── CREDITS ├── IPT-NETFLOW-MIB.my ├── Makefile.in ├── NEWS ├── README ├── README.promisc ├── compat.h ├── configure ├── dkms.conf ├── gen_compat_def ├── install-dkms.sh ├── ipt_NETFLOW.c ├── ipt_NETFLOW.h ├── irqtop ├── libipt_NETFLOW.c ├── murmur3.h ├── openwrt ├── Makefile ├── Readme.md └── patches │ └── 310-Makefile_crosscompile.patch ├── raw_promisc.patch ├── raw_promisc_debian_squeeze6.patch ├── snmp_NETFLOW.c ├── test_update_config.sh ├── testing.sh ├── travis └── Dockerfile.centos └── version.sh /.travis.yml: -------------------------------------------------------------------------------- 1 | # .travis.yml for ipt-netflow 2 | 3 | language: c 4 | dist: xenial 5 | services: 6 | - docker 7 | 8 | addons: 9 | apt: 10 | update: true 11 | packages: 12 | - pkg-config 13 | - module-assistant 14 | - iptables-dev 15 | - snmpd 16 | - libsnmp-dev 17 | 18 | matrix: 19 | include: 20 | - name: x86_64 Ubuntu 16.04.5 LTS Xenial 21 | os: linux 22 | - name: ppc64le Ubuntu 16.04.4 LTS Xenial 23 | os: linux-ppc64le 24 | - name: x86_64 CentOS 7.6.1810 25 | env: OS_NAME=centos OS_VERSION=7.6.1810 26 | - name: x86_64 CentOS 7.4.1708 27 | env: OS_NAME=centos OS_VERSION=7.4.1708 28 | - name: x86_64 CentOS 7.3.1611 29 | env: OS_NAME=centos OS_VERSION=7.3.1611 30 | - name: x86_64 CentOS 6.10 31 | env: OS_NAME=centos OS_VERSION=6.10 32 | - name: x86_64 CentOS 6.9 33 | env: OS_NAME=centos OS_VERSION=6.9 34 | - name: x86_64 CentOS 6.8 35 | env: OS_NAME=centos OS_VERSION=6.8 36 | 37 | 38 | install: 39 | - if [ -z "$OS_NAME" ]; then 40 | ( set -x; sudo m-a prepare ); 41 | else 42 | ( set -x; 43 | sudo docker pull ${OS_NAME}:${OS_VERSION}; 44 | sudo docker build --no-cache --rm --file=travis/Dockerfile.${OS_NAME} --build-arg=OS_VERSION=${OS_VERSION} --tag=${OS_NAME}-${OS_VERSION}:test .; 45 | ); 46 | fi 47 | 48 | script: 49 | - if [ -z "$OS_NAME" ]; then 50 | ( set -x; ./configure && make all && sudo make install ); 51 | else 52 | ( set -x; sudo docker run -v $PWD:$PWD -w $PWD ${OS_NAME}-${OS_VERSION}:test ); 53 | fi 54 | 55 | -------------------------------------------------------------------------------- /CREDITS: -------------------------------------------------------------------------------- 1 | License is GPL-2.0-only, is the same as of Linux kernel: 2 | 3 | This program is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 2 of the License, or 6 | (at your option) any later version. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | 16 | 17 | Sign-off rule is that of the Linux kernel: 18 | 19 | Developer's Certificate of Origin 1.1 20 | 21 | By making a contribution to this project, I certify that: 22 | 23 | (a) The contribution was created in whole or in part by me and I 24 | have the right to submit it under the open source license 25 | indicated in the file; or 26 | 27 | (b) The contribution is based upon previous work that, to the best 28 | of my knowledge, is covered under an appropriate open source 29 | license and I have the right under that license to submit that 30 | work with modifications, whether created in whole or in part 31 | by me, under the same open source license (unless I am 32 | permitted to submit under a different license), as indicated 33 | in the file; or 34 | 35 | (c) The contribution was provided directly to me by some other 36 | person who certified (a), (b) or (c) and I have not modified 37 | it. 38 | 39 | (d) I understand and agree that this project and the contribution 40 | are public and that a record of the contribution (including all 41 | personal information I submit with it, including my sign-off) is 42 | maintained indefinitely and may be redistributed consistent with 43 | this project or the open source license(s) involved. 44 | 45 | 46 | Principal author and project maintainer: 47 | 48 | ABC [2008-2021] 49 | 50 | 51 | Compatibility layer is using code from Linux Kernel and should be 52 | attributed to respective Linux developers. 53 | 54 | MurmurHash3 is based on smhasher (2012) of Austin Appleby. 55 | 56 | 57 | Patch authors and submitters: 58 | 59 | Ilya Evseev [2010] 60 | spizer [2010] 61 | Eric W. Biederman [2010] 62 | Giedrius Liubavičius [2010] 63 | Igor Alov [2010] 64 | Valentin V. Yankin [2011] prototype for SNMP-index 65 | Alexey Osipov [2011] 66 | Pavel Boldin [2012] 67 | Alexander Demenshin [2013] 68 | uropek [2013] 69 | shaman [2013] 70 | Jeremy Drake [2013] 71 | Matthew Martin [2016] DKMS fixes 72 | alex-eri [2016, 2017] OpenWRT compatibility 73 | xtaran [2018] 74 | Thadeu Lima de Souza Cascardo @ Canonical [2019] 75 | dbugnar [2019] 76 | Vadim Fedorenko [2019] 77 | Paolo Pisati @ Canonical [2020] 78 | Jeroen Roovers @ Gentoo [2020] 79 | Michael Hu [2020] 80 | Sven Hartge [2020] 81 | Simon Chopin [2021] 82 | 83 | 84 | Project supporters: 85 | 86 | Summa Telecom [2014] 87 | Starlink [2014] 88 | Anonymous 89 | 90 | 91 | Extensive testing and other help: 92 | 93 | Alexander (shulik) [2013] 94 | Igor Diakonov @ Summa Telecom [2014] 95 | Yuriy Dolgoruk @ Summa Telecom [2014] 96 | Andrew Savin @ Starlink [2014] 97 | Alexander Zakharov @ WAW Technologies [2015] 98 | Ivanov Eduard [2015] 99 | Maciej Zdeb [2015] 100 | 101 | 102 | (Send your names, emails, or nicks to add to the list.) 103 | 104 | -------------------------------------------------------------------------------- /IPT-NETFLOW-MIB.my: -------------------------------------------------------------------------------- 1 | -- IPT-NETFLOW-MIB.my 2 | 3 | IPT-NETFLOW-MIB DEFINITIONS ::= BEGIN 4 | 5 | IMPORTS 6 | MODULE-IDENTITY, OBJECT-TYPE, Counter64, 7 | Gauge32, Integer32, Counter32, enterprises 8 | FROM SNMPv2-SMI 9 | OBJECT-GROUP, MODULE-COMPLIANCE 10 | FROM SNMPv2-CONF 11 | CounterBasedGauge64 12 | FROM HCNUM-TC 13 | TEXTUAL-CONVENTION, DisplayString, DateAndTime 14 | FROM SNMPv2-TC; 15 | 16 | iptNetflowMIB MODULE-IDENTITY 17 | LAST-UPDATED "201409120000Z" 18 | ORGANIZATION "ABC" 19 | CONTACT-INFO 20 | "Author's email: abc at telekom.ru 21 | 22 | Latest version should be obtained from 23 | https://raw.githubusercontent.com/aabc/ipt-netflow/master/IPT-NETFLOW-MIB.my" 24 | 25 | DESCRIPTION 26 | "The IPT-NETFLOW-MIB defines managed objects 27 | for ipt_NETFLOW kernel module, which is high 28 | performance NetFlow/IPFIX probe for Linux. 29 | 30 | Copyright (c) 2014 . 31 | 32 | License: GPL-2.0-only" 33 | 34 | REVISION "201409110000Z" 35 | DESCRIPTION "Initial revision." 36 | 37 | ::= { enterprises 37476 9000 10 1 } 38 | 39 | -- Top Level -- 40 | iptNetflowObjects OBJECT IDENTIFIER ::= { iptNetflowMIB 1 } 41 | iptNetflowStatistics OBJECT IDENTIFIER ::= { iptNetflowMIB 2 } 42 | iptNetflowConformance OBJECT IDENTIFIER ::= { iptNetflowMIB 3 } 43 | 44 | -- Objects -- 45 | 46 | -- modinfo 47 | iptNetflowModule OBJECT IDENTIFIER ::= { iptNetflowObjects 1 } 48 | -- sysctl net.netflow 49 | iptNetflowSysctl OBJECT IDENTIFIER ::= { iptNetflowObjects 2 } 50 | 51 | -- Modinfo Objects -- 52 | 53 | name OBJECT-TYPE 54 | SYNTAX DisplayString 55 | MAX-ACCESS read-only 56 | STATUS current 57 | DESCRIPTION 58 | "Module name." 59 | ::= { iptNetflowModule 1 } 60 | 61 | version OBJECT-TYPE 62 | SYNTAX DisplayString 63 | MAX-ACCESS read-only 64 | STATUS current 65 | DESCRIPTION 66 | "Software version of the module." 67 | ::= { iptNetflowModule 2 } 68 | 69 | srcversion OBJECT-TYPE 70 | SYNTAX DisplayString 71 | MAX-ACCESS read-only 72 | STATUS current 73 | DESCRIPTION 74 | "Binary version of the module." 75 | ::= { iptNetflowModule 3 } 76 | 77 | loadTime OBJECT-TYPE 78 | SYNTAX DateAndTime 79 | MAX-ACCESS read-only 80 | STATUS current 81 | DESCRIPTION 82 | "Module load date-time." 83 | ::= { iptNetflowModule 4 } 84 | 85 | refcnt OBJECT-TYPE 86 | SYNTAX Integer32 87 | MAX-ACCESS read-only 88 | STATUS current 89 | DESCRIPTION 90 | "Module usage by other kernel objects." 91 | ::= { iptNetflowModule 5 } 92 | 93 | -- RW Sysctl objects -- 94 | 95 | protocol OBJECT-TYPE 96 | SYNTAX INTEGER { 97 | netflow5(5), 98 | netflow9(9), 99 | ipfix(10) 100 | } 101 | MAX-ACCESS read-write 102 | STATUS current 103 | DESCRIPTION 104 | "Protocol version (5, 9, 10=IPFIX)." 105 | ::= { iptNetflowSysctl 1 } 106 | 107 | hashsize OBJECT-TYPE 108 | SYNTAX Integer32 109 | UNITS "buckets" 110 | MAX-ACCESS read-write 111 | STATUS current 112 | DESCRIPTION 113 | "Hash table size of flows cache." 114 | ::= { iptNetflowSysctl 2 } 115 | 116 | maxflows OBJECT-TYPE 117 | SYNTAX Integer32 118 | UNITS "flows" 119 | MAX-ACCESS read-write 120 | STATUS current 121 | DESCRIPTION 122 | "Max flows limit. This limit is used for DoS protection." 123 | ::= { iptNetflowSysctl 3 } 124 | 125 | active-timeout OBJECT-TYPE 126 | SYNTAX Integer32 127 | UNITS "minutes" 128 | MAX-ACCESS read-write 129 | STATUS current 130 | DESCRIPTION 131 | "Active flows timeout value." 132 | ::= { iptNetflowSysctl 4 } 133 | 134 | inactive-timeout OBJECT-TYPE 135 | SYNTAX Integer32 136 | UNITS "minutes" 137 | MAX-ACCESS read-write 138 | STATUS current 139 | DESCRIPTION 140 | "Inactive flows timeout value." 141 | ::= { iptNetflowSysctl 5 } 142 | 143 | sndbuf OBJECT-TYPE 144 | SYNTAX Integer32 145 | UNITS "bytes" 146 | MAX-ACCESS read-write 147 | STATUS current 148 | DESCRIPTION 149 | "Sockets SNDBUF size." 150 | ::= { iptNetflowSysctl 6 } 151 | 152 | destination OBJECT-TYPE 153 | SYNTAX DisplayString 154 | MAX-ACCESS read-write 155 | STATUS current 156 | DESCRIPTION 157 | "Export destination parameter." 158 | ::= { iptNetflowSysctl 7 } 159 | 160 | aggregation OBJECT-TYPE 161 | SYNTAX DisplayString 162 | MAX-ACCESS read-write 163 | STATUS current 164 | DESCRIPTION 165 | "Aggregation parameters." 166 | ::= { iptNetflowSysctl 8 } 167 | 168 | sampler OBJECT-TYPE 169 | SYNTAX DisplayString 170 | MAX-ACCESS read-write 171 | STATUS current 172 | DESCRIPTION 173 | "Sampler parameters: sampling mode:sampling interval. 174 | Where samplign modes: deterministic, random, hash." 175 | ::= { iptNetflowSysctl 9 } 176 | 177 | natevents OBJECT-TYPE 178 | SYNTAX INTEGER { 179 | disabled(0), 180 | enabled(1) 181 | } 182 | MAX-ACCESS read-write 183 | STATUS current 184 | DESCRIPTION 185 | "Natevents (NEL) controlling parameter." 186 | ::= { iptNetflowSysctl 10 } 187 | 188 | promisc OBJECT-TYPE 189 | SYNTAX INTEGER { 190 | disabled(0), 191 | enabled(1) 192 | } 193 | MAX-ACCESS read-write 194 | STATUS current 195 | DESCRIPTION 196 | "Promisc hack controlling parameter." 197 | ::= { iptNetflowSysctl 11 } 198 | 199 | snmp-rules OBJECT-TYPE 200 | SYNTAX DisplayString 201 | MAX-ACCESS read-write 202 | STATUS current 203 | DESCRIPTION 204 | "SNMP-index translation rules." 205 | ::= { iptNetflowSysctl 12 } 206 | 207 | scan-min OBJECT-TYPE 208 | SYNTAX Integer32 209 | MAX-ACCESS read-write 210 | STATUS current 211 | DESCRIPTION 212 | "scan-min parameter." 213 | ::= { iptNetflowSysctl 13 } 214 | 215 | -- Statistics Objects -- 216 | 217 | iptNetflowTotals OBJECT IDENTIFIER ::= { iptNetflowStatistics 1 } 218 | 219 | inBitRate OBJECT-TYPE 220 | SYNTAX CounterBasedGauge64 221 | UNITS "bits/second" 222 | MAX-ACCESS read-only 223 | STATUS current 224 | DESCRIPTION 225 | "Total incoming bits per second." 226 | ::= { iptNetflowTotals 1 } 227 | 228 | inPacketRate OBJECT-TYPE 229 | SYNTAX Gauge32 230 | UNITS "packets/second" 231 | MAX-ACCESS read-only 232 | STATUS current 233 | DESCRIPTION 234 | "Total incoming packets per second." 235 | ::= { iptNetflowTotals 2 } 236 | 237 | inFlows OBJECT-TYPE 238 | SYNTAX Counter64 239 | UNITS "flows" 240 | MAX-ACCESS read-only 241 | STATUS current 242 | DESCRIPTION 243 | "Total observed (metered) flows." 244 | ::= { iptNetflowTotals 3 } 245 | 246 | inPackets OBJECT-TYPE 247 | SYNTAX Counter64 248 | UNITS "packets" 249 | MAX-ACCESS read-only 250 | STATUS current 251 | DESCRIPTION 252 | "Total metered packets. Not couning dropped packets." 253 | ::= { iptNetflowTotals 4 } 254 | 255 | inBytes OBJECT-TYPE 256 | SYNTAX Counter64 257 | UNITS "bytes" 258 | MAX-ACCESS read-only 259 | STATUS current 260 | DESCRIPTION 261 | "Total metered bytes in inPackets." 262 | ::= { iptNetflowTotals 5 } 263 | 264 | FixedDiv100 ::= TEXTUAL-CONVENTION 265 | DISPLAY-HINT "d-2" 266 | STATUS current 267 | DESCRIPTION "Fixed point, two decimals." 268 | SYNTAX Gauge32 269 | 270 | hashMetric OBJECT-TYPE 271 | SYNTAX FixedDiv100 272 | MAX-ACCESS read-only 273 | STATUS current 274 | DESCRIPTION 275 | "Measure of performance of hash table. When optimal should 276 | attract to 1.0, when non-optimal will be highly above of 1." 277 | ::= { iptNetflowTotals 6 } 278 | 279 | hashMemory OBJECT-TYPE 280 | SYNTAX Gauge32 281 | UNITS "bytes" 282 | MAX-ACCESS read-only 283 | STATUS current 284 | DESCRIPTION 285 | "How much system memory is used by the hash table." 286 | ::= { iptNetflowTotals 7 } 287 | 288 | hashFlows OBJECT-TYPE 289 | SYNTAX Gauge32 290 | UNITS "flows" 291 | MAX-ACCESS read-only 292 | STATUS current 293 | DESCRIPTION 294 | "Flows currently residing in the hash table and not 295 | exported yet." 296 | ::= { iptNetflowTotals 8 } 297 | 298 | hashPackets OBJECT-TYPE 299 | SYNTAX Gauge32 300 | UNITS "packets" 301 | MAX-ACCESS read-only 302 | STATUS current 303 | DESCRIPTION 304 | "Packets in flows currently residing in the hash table." 305 | ::= { iptNetflowTotals 9 } 306 | 307 | hashBytes OBJECT-TYPE 308 | SYNTAX CounterBasedGauge64 309 | UNITS "bytes" 310 | MAX-ACCESS read-only 311 | STATUS current 312 | DESCRIPTION 313 | "Bytes in flows currently residing in the hash table." 314 | ::= { iptNetflowTotals 10 } 315 | 316 | dropPackets OBJECT-TYPE 317 | SYNTAX Counter64 318 | UNITS "packets" 319 | MAX-ACCESS read-only 320 | STATUS current 321 | DESCRIPTION 322 | "Total packets dropped by metering process." 323 | ::= { iptNetflowTotals 11 } 324 | 325 | dropBytes OBJECT-TYPE 326 | SYNTAX Counter64 327 | UNITS "bytes" 328 | MAX-ACCESS read-only 329 | STATUS current 330 | DESCRIPTION 331 | "Total bytes in packets dropped by metering process." 332 | ::= { iptNetflowTotals 12 } 333 | 334 | outByteRate OBJECT-TYPE 335 | SYNTAX Gauge32 336 | UNITS "bytes/second" 337 | MAX-ACCESS read-only 338 | STATUS current 339 | DESCRIPTION 340 | "Total exporter output bytes per second." 341 | ::= { iptNetflowTotals 13 } 342 | 343 | outFlows OBJECT-TYPE 344 | SYNTAX Counter64 345 | UNITS "flows" 346 | MAX-ACCESS read-only 347 | STATUS current 348 | DESCRIPTION 349 | "Total exported flow data records." 350 | ::= { iptNetflowTotals 14 } 351 | 352 | outPackets OBJECT-TYPE 353 | SYNTAX Counter64 354 | UNITS "packets" 355 | MAX-ACCESS read-only 356 | STATUS current 357 | DESCRIPTION 358 | "Total exported packets of netflow stream itself." 359 | ::= { iptNetflowTotals 15 } 360 | 361 | outBytes OBJECT-TYPE 362 | SYNTAX Counter64 363 | UNITS "bytes" 364 | MAX-ACCESS read-only 365 | STATUS current 366 | DESCRIPTION 367 | "Total exported bytes of netflow stream itself." 368 | ::= { iptNetflowTotals 16 } 369 | 370 | lostFlows OBJECT-TYPE 371 | SYNTAX Counter64 372 | UNITS "flows" 373 | MAX-ACCESS read-only 374 | STATUS current 375 | DESCRIPTION 376 | "Total of accounted flows that are lost by exporting process 377 | due to socket errors. This value will not include asynchronous 378 | errors (cberr), these will be counted in errTotal." 379 | ::= { iptNetflowTotals 17 } 380 | 381 | lostPackets OBJECT-TYPE 382 | SYNTAX Counter64 383 | UNITS "packets" 384 | MAX-ACCESS read-only 385 | STATUS current 386 | DESCRIPTION 387 | "Total metered packets lost by exporting process. 388 | See lostFlows for details." 389 | ::= { iptNetflowTotals 18 } 390 | 391 | lostBytes OBJECT-TYPE 392 | SYNTAX Counter64 393 | UNITS "bytes" 394 | MAX-ACCESS read-only 395 | STATUS current 396 | DESCRIPTION 397 | "Total bytes in packets lost by exporting process. 398 | See lostFlows for details." 399 | ::= { iptNetflowTotals 19 } 400 | 401 | errTotal OBJECT-TYPE 402 | SYNTAX Counter32 403 | MAX-ACCESS read-only 404 | STATUS current 405 | DESCRIPTION 406 | "Total exporting sockets errors (including cberr)." 407 | ::= { iptNetflowTotals 20 } 408 | 409 | sndbufPeak OBJECT-TYPE 410 | SYNTAX Counter32 411 | UNITS "bytes" 412 | MAX-ACCESS read-only 413 | STATUS current 414 | DESCRIPTION 415 | "Global maximum value of socket sndbuf. Sort of output 416 | queue length." 417 | ::= { iptNetflowTotals 21 } 418 | 419 | -- Per CPU statistics -- 420 | 421 | iptNetflowCpuTable OBJECT-TYPE 422 | SYNTAX SEQUENCE OF IptNetflowCpuEntry 423 | MAX-ACCESS not-accessible 424 | STATUS current 425 | DESCRIPTION 426 | "Per-CPU statistics." 427 | ::= { iptNetflowStatistics 2 } 428 | 429 | iptNetflowCpuEntry OBJECT-TYPE 430 | SYNTAX IptNetflowCpuEntry 431 | MAX-ACCESS not-accessible 432 | STATUS current 433 | DESCRIPTION 434 | "Defines an entry in the iptNetflowCpuTable." 435 | INDEX { cpuIndex } 436 | ::= { iptNetflowCpuTable 1 } 437 | 438 | IptNetflowCpuEntry ::= 439 | SEQUENCE { 440 | cpuIndex INTEGER, 441 | cpuInPacketRate Gauge32, 442 | cpuInFlows Counter64, 443 | cpuInPackets Counter64, 444 | cpuInBytes Counter64, 445 | cpuHashMetric FixedDiv100, 446 | cpuDropPackets Counter64, 447 | cpuDropBytes Counter64, 448 | cpuErrTrunc Counter32, 449 | cpuErrFrag Counter32, 450 | cpuErrAlloc Counter32, 451 | cpuErrMaxflows Counter32 452 | } 453 | 454 | cpuIndex OBJECT-TYPE 455 | SYNTAX Integer32 (0..4096) 456 | MAX-ACCESS read-only 457 | STATUS current 458 | DESCRIPTION 459 | "Index of this cpu." 460 | ::= { iptNetflowCpuEntry 1 } 461 | 462 | cpuInPacketRate OBJECT-TYPE 463 | SYNTAX Gauge32 464 | UNITS "packets/second" 465 | MAX-ACCESS read-only 466 | STATUS current 467 | DESCRIPTION 468 | "Incoming packets per second for this cpu." 469 | ::= { iptNetflowCpuEntry 2 } 470 | 471 | cpuInFlows OBJECT-TYPE 472 | SYNTAX Counter64 473 | UNITS "flows" 474 | MAX-ACCESS read-only 475 | STATUS current 476 | DESCRIPTION 477 | "Flows metered on this cpu." 478 | ::= { iptNetflowCpuEntry 3 } 479 | 480 | cpuInPackets OBJECT-TYPE 481 | SYNTAX Counter64 482 | UNITS "packets" 483 | MAX-ACCESS read-only 484 | STATUS current 485 | DESCRIPTION 486 | "Packets metered for cpuIndex." 487 | ::= { iptNetflowCpuEntry 4 } 488 | 489 | cpuInBytes OBJECT-TYPE 490 | SYNTAX Counter64 491 | UNITS "bytes" 492 | MAX-ACCESS read-only 493 | STATUS current 494 | DESCRIPTION 495 | "Bytes metered on this cpu." 496 | ::= { iptNetflowCpuEntry 5 } 497 | 498 | cpuHashMetric OBJECT-TYPE 499 | SYNTAX FixedDiv100 500 | MAX-ACCESS read-only 501 | STATUS current 502 | DESCRIPTION 503 | "Measure of performance of hash table on this cpu." 504 | ::= { iptNetflowCpuEntry 6 } 505 | 506 | cpuDropPackets OBJECT-TYPE 507 | SYNTAX Counter64 508 | UNITS "packets" 509 | MAX-ACCESS read-only 510 | STATUS current 511 | DESCRIPTION 512 | "Packets dropped by metering process on this cpu." 513 | ::= { iptNetflowCpuEntry 7 } 514 | 515 | cpuDropBytes OBJECT-TYPE 516 | SYNTAX Counter64 517 | UNITS "bytes" 518 | MAX-ACCESS read-only 519 | STATUS current 520 | DESCRIPTION 521 | "Bytes in cpuDropPackets for this cpu." 522 | ::= { iptNetflowCpuEntry 8 } 523 | 524 | cpuErrTrunc OBJECT-TYPE 525 | SYNTAX Counter32 526 | MAX-ACCESS read-only 527 | STATUS current 528 | DESCRIPTION 529 | "Truncated packets dropped for this cpu." 530 | ::= { iptNetflowCpuEntry 9 } 531 | 532 | cpuErrFrag OBJECT-TYPE 533 | SYNTAX Counter32 534 | MAX-ACCESS read-only 535 | STATUS current 536 | DESCRIPTION 537 | "Fragmented packets dropped for this cpu." 538 | ::= { iptNetflowCpuEntry 10 } 539 | 540 | cpuErrAlloc OBJECT-TYPE 541 | SYNTAX Counter32 542 | MAX-ACCESS read-only 543 | STATUS current 544 | DESCRIPTION 545 | "Packets dropped due to memory allocation errors." 546 | ::= { iptNetflowCpuEntry 11 } 547 | 548 | cpuErrMaxflows OBJECT-TYPE 549 | SYNTAX Counter32 550 | MAX-ACCESS read-only 551 | STATUS current 552 | DESCRIPTION 553 | "Packets dropped due to maxflows limit being reached." 554 | ::= { iptNetflowCpuEntry 12 } 555 | 556 | -- Per Socket statistics -- 557 | 558 | iptNetflowSockTable OBJECT-TYPE 559 | SYNTAX SEQUENCE OF IptNetflowSockEntry 560 | MAX-ACCESS not-accessible 561 | STATUS current 562 | DESCRIPTION 563 | "Per socket statistics." 564 | ::= { iptNetflowStatistics 3 } 565 | 566 | iptNetflowSockEntry OBJECT-TYPE 567 | SYNTAX IptNetflowSockEntry 568 | MAX-ACCESS not-accessible 569 | STATUS current 570 | DESCRIPTION 571 | "Defines an entry in the iptNetflowSockTable." 572 | INDEX { sockIndex } 573 | ::= { iptNetflowSockTable 1 } 574 | 575 | IptNetflowSockEntry ::= 576 | SEQUENCE { 577 | sockIndex INTEGER, 578 | sockDestination DisplayString, 579 | sockActive INTEGER, 580 | sockErrConnect Counter32, 581 | sockErrFull Counter32, 582 | sockErrCberr Counter32, 583 | sockErrOther Counter32, 584 | sockSndbuf Gauge32, 585 | sockSndbufFill Gauge32, 586 | sockSndbufPeak Gauge32 587 | } 588 | 589 | sockIndex OBJECT-TYPE 590 | SYNTAX Integer32 (0..4096) 591 | MAX-ACCESS not-accessible 592 | STATUS current 593 | DESCRIPTION 594 | "Exporting socket index." 595 | ::= { iptNetflowSockEntry 1 } 596 | 597 | sockDestination OBJECT-TYPE 598 | SYNTAX DisplayString 599 | MAX-ACCESS read-only 600 | STATUS current 601 | DESCRIPTION 602 | "Exporting connection destination of this socket." 603 | ::= { iptNetflowSockEntry 2 } 604 | 605 | sockActive OBJECT-TYPE 606 | SYNTAX INTEGER { 607 | inactive(0), 608 | active(1) 609 | } 610 | MAX-ACCESS read-only 611 | STATUS current 612 | DESCRIPTION 613 | "Connection state of this socket." 614 | ::= { iptNetflowSockEntry 3 } 615 | 616 | sockErrConnect OBJECT-TYPE 617 | SYNTAX Counter32 618 | MAX-ACCESS read-only 619 | STATUS current 620 | DESCRIPTION 621 | "Connections attempt count. High value usually mean 622 | that network is not set up properly, or module is loaded 623 | before network is up, in this case it is not dangerous 624 | and should be ignored." 625 | ::= { iptNetflowSockEntry 4 } 626 | 627 | sockErrFull OBJECT-TYPE 628 | SYNTAX Counter32 629 | MAX-ACCESS read-only 630 | STATUS current 631 | DESCRIPTION 632 | "Socket full errors on this socket. Usually mean sndbuf 633 | value is too small." 634 | ::= { iptNetflowSockEntry 5 } 635 | 636 | sockErrCberr OBJECT-TYPE 637 | SYNTAX Counter32 638 | MAX-ACCESS read-only 639 | STATUS current 640 | DESCRIPTION 641 | "Asynchronous callback errors on this socket. Usually mean 642 | that there is 'connection refused' errors on UDP socket 643 | reported via ICMP messages." 644 | ::= { iptNetflowSockEntry 6 } 645 | 646 | sockErrOther OBJECT-TYPE 647 | SYNTAX Counter32 648 | MAX-ACCESS read-only 649 | STATUS current 650 | DESCRIPTION 651 | "All other possible errors on this socket." 652 | ::= { iptNetflowSockEntry 7 } 653 | 654 | sockSndbuf OBJECT-TYPE 655 | SYNTAX Gauge32 656 | UNITS "bytes" 657 | MAX-ACCESS read-only 658 | STATUS current 659 | DESCRIPTION 660 | "Sndbuf value for this socket. Higher value allows accommodate 661 | (exporting) traffic bursts." 662 | ::= { iptNetflowSockEntry 8 } 663 | 664 | sockSndbufFill OBJECT-TYPE 665 | SYNTAX Gauge32 666 | UNITS "bytes" 667 | MAX-ACCESS read-only 668 | STATUS current 669 | DESCRIPTION 670 | "Amount of data currently in socket buffers. When this value 671 | will reach size sndbuf, packet loss will occur." 672 | ::= { iptNetflowSockEntry 9 } 673 | 674 | sockSndbufPeak OBJECT-TYPE 675 | SYNTAX Gauge32 676 | UNITS "bytes" 677 | MAX-ACCESS read-only 678 | STATUS current 679 | DESCRIPTION 680 | "Historical peak amount of data in socket buffers. Useful to 681 | evaluate sndbuf size, because sockSndbufFill is transient." 682 | ::= { iptNetflowSockEntry 10 } 683 | 684 | -- Conformance Information -- 685 | 686 | iptNetflowCompliances OBJECT IDENTIFIER ::= { iptNetflowConformance 1 } 687 | iptNetflowGroups OBJECT IDENTIFIER ::= { iptNetflowConformance 2 } 688 | 689 | iptNetflowCompliance MODULE-COMPLIANCE 690 | STATUS current 691 | DESCRIPTION "iptNetflowCompliance" 692 | MODULE 693 | MANDATORY-GROUPS { 694 | iptNetflowModuleGroup, 695 | iptNetflowSysctlGroup, 696 | iptNetflowTotalsGroup, 697 | iptNetflowCpuGroup, 698 | iptNetflowSockGroup 699 | } 700 | ::= { iptNetflowCompliances 1 } 701 | 702 | iptNetflowModuleGroup OBJECT-GROUP 703 | OBJECTS { 704 | name, 705 | version, 706 | srcversion, 707 | loadTime, 708 | refcnt 709 | } 710 | STATUS current 711 | DESCRIPTION "Modinfo." 712 | ::= { iptNetflowGroups 1 } 713 | 714 | iptNetflowSysctlGroup OBJECT-GROUP 715 | OBJECTS { 716 | hashsize, 717 | maxflows, 718 | protocol, 719 | active-timeout, 720 | inactive-timeout, 721 | sndbuf, 722 | destination, 723 | aggregation, 724 | sampler, 725 | natevents, 726 | promisc, 727 | snmp-rules, 728 | scan-min 729 | } 730 | STATUS current 731 | DESCRIPTION "Read-write objects accessed via sysctl" 732 | ::= { iptNetflowGroups 2 } 733 | 734 | iptNetflowTotalsGroup OBJECT-GROUP 735 | OBJECTS { 736 | inBitRate, 737 | inPacketRate, 738 | inFlows, 739 | inPackets, 740 | inBytes, 741 | hashMetric, 742 | hashMemory, 743 | hashFlows, 744 | hashPackets, 745 | hashBytes, 746 | dropPackets, 747 | dropBytes, 748 | outByteRate, 749 | outFlows, 750 | outPackets, 751 | outBytes, 752 | lostFlows, 753 | lostPackets, 754 | lostBytes, 755 | errTotal, 756 | sndbufPeak 757 | } 758 | STATUS current 759 | DESCRIPTION "Statistics totals." 760 | ::= { iptNetflowGroups 3 } 761 | 762 | iptNetflowCpuGroup OBJECT-GROUP 763 | OBJECTS { 764 | cpuIndex, 765 | cpuInPacketRate, 766 | cpuInFlows, 767 | cpuInPackets, 768 | cpuInBytes, 769 | cpuHashMetric, 770 | cpuDropPackets, 771 | cpuDropBytes, 772 | cpuErrTrunc, 773 | cpuErrFrag, 774 | cpuErrAlloc, 775 | cpuErrMaxflows 776 | } 777 | STATUS current 778 | DESCRIPTION "Per CPU statistics." 779 | ::= { iptNetflowGroups 4 } 780 | 781 | iptNetflowSockGroup OBJECT-GROUP 782 | OBJECTS { 783 | sockDestination, 784 | sockActive, 785 | sockErrConnect, 786 | sockErrFull, 787 | sockErrCberr, 788 | sockErrOther, 789 | sockSndbuf, 790 | sockSndbufFill, 791 | sockSndbufPeak 792 | } 793 | STATUS current 794 | DESCRIPTION "Per socket statistics." 795 | ::= { iptNetflowGroups 5 } 796 | 797 | END 798 | -------------------------------------------------------------------------------- /Makefile.in: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-2.0-only 2 | # 3 | # Edit Makefile.in and run ./configure 4 | 5 | KVERSION = @KVERSION@ 6 | KDIR = @KDIR@ 7 | KINSTDIR = $(shell dirname @KDIR@) 8 | KOPTS = @KOPTS@ 9 | IPTABLES_CFLAGS = @IPTABLES_CFLAGS@ 10 | IPTABLES_MODULES = @IPTABLES_MODULES@ 11 | DEPMOD = /sbin/depmod -a 12 | CARGS = @CARGS@ 13 | SNMPTGSO = /usr/lib/snmp/dlmod/snmp_NETFLOW.so 14 | SNMPCONF = /etc/snmp/snmpd.conf 15 | SNMPLINE = dlmod netflow $(SNMPTGSO) 16 | CC = gcc 17 | 18 | # https://www.kernel.org/doc/Documentation/kbuild/modules.txt 19 | # https://www.kernel.org/doc/Documentation/kbuild/makefiles.txt 20 | obj-m = ipt_NETFLOW.o 21 | ccflags-y = @KOPTS@ 22 | 23 | all: ipt_NETFLOW.ko libipt_NETFLOW.so libip6t_NETFLOW.so @SNMPTARGET@ 24 | 25 | ipt_NETFLOW.ko: version.h ipt_NETFLOW.c ipt_NETFLOW.h compat_def.h compat.h Makefile 26 | @echo Compiling $(shell ./version.sh) for kernel $(KVERSION) 27 | make -C $(KDIR) M=$(CURDIR) modules 28 | @touch $@ 29 | compat_def.h: gen_compat_def 30 | ./gen_compat_def > $@- 31 | mv $@- $@ 32 | sparse: | version.h ipt_NETFLOW.c ipt_NETFLOW.h compat.h Makefile 33 | @rm -f ipt_NETFLOW.ko ipt_NETFLOW.o 34 | @echo Compiling for kernel $(KVERSION) 35 | make -C $(KDIR) M=$(CURDIR) modules C=1 36 | @touch ipt_NETFLOW.ko 37 | coverity: 38 | coverity-submit -v 39 | 40 | minstall: | ipt_NETFLOW.ko 41 | @echo " *" 42 | make -C $(KDIR) M=$(CURDIR) modules_install INSTALL_MOD_PATH=$(DESTDIR) 43 | $(DEPMOD) 44 | mclean: 45 | make -C $(KDIR) M=$(CURDIR) clean 46 | lclean: 47 | -rm -f *.so *_sh.o 48 | clean: mclean lclean 49 | -rm -f *.so *.o modules.order version.h compat_def.h 50 | 51 | snmp_NETFLOW.so: snmp_NETFLOW.c 52 | $(CC) -fPIC -shared -o $@ $< -lnetsnmp 53 | 54 | sinstall: | snmp_NETFLOW.so IPT-NETFLOW-MIB.my 55 | @echo " *" 56 | install -D IPT-NETFLOW-MIB.my $(DESTDIR)/usr/share/snmp/mibs/IPT-NETFLOW-MIB.my 57 | install -D snmp_NETFLOW.so $(DESTDIR)$(SNMPTGSO) 58 | @if ! grep -E -qs "^ *$(SNMPLINE)" $(SNMPCONF); then \ 59 | echo " *"; \ 60 | echo " * Add this line to $(SNMPCONF) to enable IPT-NETFLOW-MIB:"; \ 61 | echo " *"; \ 62 | echo " * $(SNMPLINE)"; \ 63 | echo " *"; \ 64 | fi 65 | @if killall -0 snmpd >/dev/null 2>&1; then \ 66 | echo " * (snmpd needs restart for changes to take effect.)"; \ 67 | else \ 68 | echo " * (snmpd is not started.)"; \ 69 | fi 70 | 71 | %_sh.o: libipt_NETFLOW.c 72 | $(CC) $(CFLAGS) -O2 -Wall -Wunused $(IPTABLES_CFLAGS) -fPIC -o $@ -c libipt_NETFLOW.c 73 | 74 | %.so: %_sh.o 75 | $(CC) -shared -o $@ $< 76 | 77 | version.h: ipt_NETFLOW.c ipt_NETFLOW.h compat.h Makefile 78 | @./version.sh --define > version.h 79 | 80 | linstall: | libipt_NETFLOW.so libip6t_NETFLOW.so 81 | @echo " *" 82 | install -D libipt_NETFLOW.so $(DESTDIR)$(IPTABLES_MODULES)/libipt_NETFLOW.so 83 | install -D libip6t_NETFLOW.so $(DESTDIR)$(IPTABLES_MODULES)/libip6t_NETFLOW.so 84 | 85 | dinstall: 86 | @echo " *" 87 | @./install-dkms.sh --install 88 | 89 | install: minstall linstall @DKMSINSTALL@ @SNMPINSTALL@ 90 | 91 | uninstall: 92 | -rm -f $(DESTDIR)$(IPTABLES_MODULES)/libipt_NETFLOW.so 93 | -rm -f $(DESTDIR)$(IPTABLES_MODULES)/libip6t_NETFLOW.so 94 | -rm -f $(DESTDIR)/usr/share/snmp/mibs/IPT-NETFLOW-MIB.my 95 | -rm -f $(DESTDIR)$(SNMPTGSO) 96 | @if grep -E -qs "^ *$(SNMPLINE)" $(SNMPCONF); then \ 97 | echo " *"; \ 98 | echo " * Remove this line from $(SNMPCONF):"; \ 99 | echo " *"; \ 100 | echo " * "`grep -E "^ *$(SNMPLINE)" $(SNMPCONF)`; \ 101 | echo " *"; \ 102 | fi 103 | @if [ "@DKMSINSTALL@" = dinstall ]; then ./install-dkms.sh --uninstall; fi 104 | -rm -f $(DESTDIR)$(KINSTDIR)/extra/ipt_NETFLOW.ko 105 | 106 | Makefile: Makefile.in configure 107 | ./configure --make ${CARGS} 108 | 109 | load: all 110 | -insmod ipt_NETFLOW.ko active_timeout=5 protocol=9 111 | -iptables -I OUTPUT -j NETFLOW 112 | -iptables -I INPUT -j NETFLOW 113 | -ip6tables -I OUTPUT -j NETFLOW 114 | -ip6tables -I INPUT -j NETFLOW 115 | 116 | unload: 117 | -iptables -D OUTPUT -j NETFLOW 118 | -iptables -D INPUT -j NETFLOW 119 | -ip6tables -D OUTPUT -j NETFLOW 120 | -ip6tables -D INPUT -j NETFLOW 121 | -rmmod ipt_NETFLOW.ko 122 | 123 | reload: unload load 124 | 125 | ChangeLog: 126 | gitlog-to-changelog > ChangeLog 127 | .PHONY: ChangeLog 128 | 129 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | ipt-netflow NEWS 2 | ================ 3 | 4 | 2.6 (2021-05-15) 5 | * Minor feature and maintenance release. 6 | - Compilation compatibility with kernel 5.12. 7 | - Add ipVersion (60) support. 8 | - Optionally seed initial template ID from PRNG. 9 | - Compilation improvements. 10 | 11 | 2.5.1 (2020-08-12) 12 | * Maintenance release. 13 | - Fix soft lockup on kernels with xtables targets used via nftables. 14 | - Fix compilation with Linux 5.8 and with CentOS 8. 15 | 16 | 2.5 (2020-04-24) 17 | * Minor maintenance release. 18 | - Compilation compatibility with kernels up to 5.6. 19 | - Performance improvements by Vadim Fedorenko. 20 | - Small code fixes and typo corrections. 21 | 22 | 2.4 (2019-06-23) 23 | * Minor maintenance release. 24 | - Compilation compatibility with kernels up to 5.2. 25 | - README, CREDITS update. 26 | 27 | 2.3 (2018-03-19) 28 | 29 | * Minor feature and Maintenance release. 30 | - Compatibility with latest kernels. 31 | - Allow to set engine_id (observationDomainId). 32 | - Cross-compilation support. 33 | - OpenWRT support. 34 | - Allow binding destination socket to IP and interface. 35 | 36 | 2.2 (2016-02-21) 37 | 38 | * Minor feature and Maintenance release. 39 | - Decapsulate MPLS in promisc mode and MPLS-aware NetFlow feature. 40 | - Export flowEndReason for IPFIX. 41 | - Promics mode improvements. 42 | - Allow export destination to be IPv6 address. 43 | - Move flows list from debugfs to proc. 44 | - Compilation compatibility with latest kernels. 45 | - Code is Coverity scanned. 46 | 47 | 2.1 (2014-02-08) 48 | 49 | * Options Templates support (V9 and IPFIX). Which let to implement: 50 | - Flow Sampling (random, deterministic, and hash modes) for all types 51 | of NetFlow protocols (V5, V9, IPFIX). 52 | - Export Statistics (metering, exporting, sampling) and Configuration. 53 | - Export Interface list (ifName, ifDescr). 54 | * Promisc hack (no need to patch kernel anymore). 55 | * SNMP monitoring interface and agent (via net-snmp dlmod). 56 | * More compilation compatibility with recent kernels, grsecurity kernels, 57 | Gentoo, Debian, Centos. DKMS install support. 58 | * Minor features: IPSec flows, Direction Element. Removed support for 59 | CONNMARK. Bug fixes and improvements. 60 | * irqtop tool (ruby). 61 | 62 | 2.0.1 (2014-09-04) 63 | 64 | * Minor fixes for 2.0 release. 65 | 66 | 2.0 (2014-08-07) 67 | 68 | * This is major release with a lot of new features and improvements, such 69 | as: 70 | - Support of NetFlow v9 and IPFIX. 71 | - IPv6 support. 72 | - NAT translation events (NEL). 73 | - Additional options is SNMP-index translation rules, Ethernet Type, 74 | VLAN, and MAC addresses exporting. 75 | - Performance improvements (tested to work well on 10Gbit load). 76 | - Stability improvements and bug fixes. 77 | 78 | 1.8 (2012-07-02) 79 | 80 | * This is minor bug fix release with small improvements. 81 | 82 | 1.7.1 (2011-04-04) 83 | 84 | * This is minor release with improved compilation compatibility and small 85 | improvements. 86 | 87 | 1.7 (2011-01-30) 88 | 89 | * This version have improved compilation compatibility with latest Linux 90 | kernels (2.6.36.3 and 2.6.27) and bunch of small improvements. 91 | 92 | * Since version 1.7 ipt-netflow's repository moved to Git SCM. Use of CVS 93 | repository is deprecated. 94 | 95 | 1.5.1 (2009-03-14) 96 | 97 | * This version have improved compliance to NetFlow standard and 98 | compatibility with iptables/xtables 1.4.x. Added options to configure 99 | script for manual customization. 100 | 101 | 1.4 (2008-12-23) 102 | 103 | * This version have restored compatibility with popular kernel 2.6.18, 104 | added configure script, statistics improvements, some fixes for 64-bit 105 | platforms, and minor performance tune up. 106 | 107 | 1.2 (2008-11-15) 108 | 109 | * This version have stability enhancements, documentation improvements, IP 110 | frag support, better statistics. 111 | 112 | 1.1 (2008-08-06) 113 | 114 | * This version updated compatibility with latest (2.6.26) Linux kernel, have 115 | more support for promisc patch, and minor fixes. 116 | 117 | 1.0 (2008-07-12) 118 | 119 | * First release tested in production environment. 120 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | ipt_NETFLOW linux 2.6.x-5.x kernel module by -- 2008-2021. 2 | 3 | High performance NetFlow v5, v9, IPFIX flow data export module for Linux 4 | kernel. Created to be useful for linux routers in high-throughput networks. 5 | It should be used as iptables target. 6 | 7 | 8 | ========================= 9 | = Detailed Feature List = 10 | ========================= 11 | 12 | * High performance and scalability. For highest performance module could be 13 | run without conntrack being enabled in kernel. Reported to be able to 14 | handle 10Gbit traffic with more than 1500000 pps with negligible server 15 | load (on S5500BC). 16 | 17 | * NetFlow v5, v9, and IPFIX are fully supported. 18 | 19 | Support of v9/IPFIX is adding flexibility to exporting of flow data 20 | plus greater visibility of traffic, letting export many additional fields 21 | besides what was possible in v5 era. Such as 22 | 23 | * IPv6 option headers, IPv4 options, TCP options, ethernet type, dot1q 24 | service and customer VLAN ids, MAC addresses, and 25 | 26 | * Full IPv6 support, 27 | 28 | * NAT translations events (from conntrack) using NetFlow Event Logging (NEL). 29 | This is standardized way for v9/IPFIXr, but module export such events even 30 | for v5 collectors via specially crafted pseudo-records. 31 | 32 | * Deterministic (systematic count-based), random and hash Flow Sampling. 33 | With appropriate differences in support of v5, v9, and IPFIX. 34 | 35 | * SNMP agent (for net-snmp) for remote management and monitoring. 36 | 37 | * Options Templates (v9/IPFIX) let export useful statistical, 38 | configurational, and informational records to collector. 39 | Such as metering, exporting, sampling stat and reliability stat, sampling 40 | configuration, network devices ifName, ifDescr list. 41 | 42 | * Tested to compile and work out of the box on Centos 6, 7, Debian and 43 | * Ubuntu. Many vanilla Linux kernels since 2.6.18 up to the latest (as of 44 | * writing is 3.19) are supported and tested. 45 | 46 | * Module load time and run-time (via sysctl) configuration. 47 | 48 | * Flexibility in enabling features via ./configure script. This will let you 49 | disable features you don't need, which increase compatibility with custom 50 | kernels and performance. 51 | 52 | * SNMP-index translation rules, let convert meaningless and unstable 53 | interface indexes (ifIndex) to more meaningful numbering scheme. 54 | 55 | * Easy support for catching mirrored traffic with promisc option. Which is 56 | also supporting optional MPLS decapsulation and MPLS-aware NetFlow. 57 | 58 | 59 | ============================ 60 | = OBTAINING LATEST VERSION = 61 | ============================ 62 | 63 | $ git clone git://github.com/aabc/ipt-netflow.git ipt-netflow 64 | $ cd ipt-netflow 65 | 66 | 67 | ================ 68 | = INSTALLATION = 69 | ================ 70 | 71 | Five easy steps. 72 | 73 | ** 1. Prepare Kernel source 74 | 75 | If you have package system install kernel-devel package, otherwise install 76 | raw kernel source from http://kernel.org matching _exactly_ version of your 77 | installed kernel. 78 | 79 | a) What to do for Centos: 80 | 81 | ~# yum install kernel-devel 82 | 83 | b) What to do for Debian and Ubuntu: 84 | 85 | ~# apt-get install module-assistant 86 | ~# m-a prepare 87 | 88 | c) Otherwise, if you downloaded raw kernel sources don't forget to create 89 | .config by copying it from your distribution's kernel. Its copy could reside 90 | in /boot or sometimes in /proc, examples: 91 | 92 | kernel-src-dir/# cp /boot/config-`uname -r` .config 93 | or 94 | kernel-src-dir/# zcat /proc/config.gz > .config 95 | 96 | Assuming you unpacked kernel source into `kernel-src-dir/' directory. 97 | Then run: 98 | 99 | kernel-src-dir/# make oldconfig 100 | 101 | After that you'll need to prepare kernel for modules build: 102 | 103 | kernel-src-dir/# make prepare modules_prepare 104 | 105 | Note: Don't try to `make prepare' in Centos kernel-devel package directory 106 | (which is usually something like /usr/src/kernels/2.6.32-431.el6.x86_64) 107 | as this is wrong and meaningless. 108 | 109 | ** 2. Prepare Iptables 110 | 111 | Before this step it also would be useful to install pkg-config if don't 112 | already have. 113 | 114 | If you have package system just install iptables-devel (or on Debian, Ubuntu 115 | and derivatives libxtables-dev if available, otherwise iptables-dev) 116 | package, otherwise install iptables source matching version of your 117 | installation from ftp://ftp.netfilter.org/pub/iptables/ 118 | 119 | a) What to do for Centos: 120 | 121 | # yum install iptables-devel 122 | 123 | b) What to do for Debian or Ubuntu: 124 | 125 | # apt-get install iptables-dev pkg-config 126 | 127 | c) Otherwise, for raw iptables source build it and make install. 128 | 129 | ** 3. Prepare net-snmp (optional) 130 | 131 | In case you want to manage or monitor module performance via SNMP you 132 | may install net-snmp. If you want to skip this step run configure 133 | with --disable-snmp-agent option. 134 | 135 | a) For Centos: 136 | 137 | # yum install net-snmp net-snmp-devel 138 | 139 | b) For Debian or Ubuntu: 140 | 141 | # apt-get install snmpd libsnmp-dev 142 | 143 | c) Otherwise install net-snmp from www.net-snmp.org 144 | 145 | ** 4. Now, to actually build the module run: 146 | 147 | ~/ipt-netflow# ./configure 148 | ~/ipt-netflow# make all install 149 | ~/ipt-netflow# depmod 150 | 151 | This will install kernel module and iptables specific library. 152 | 153 | Troubleshooting: 154 | 155 | a) Sometimes you will want to add CC=gcc-3 to make command. 156 | Example: make CC=gcc-3.3 157 | 158 | b) Compile module with actual kernel source compiled. 159 | I.e. first compile kernel and boot into it, and then compile module. 160 | If you are using kernel-devel package check that its version matches 161 | your kernel package. 162 | 163 | c) If you have sources in non-standard places or configure isn't able to 164 | find something run ./configure --help to see how to specify paths manually. 165 | 166 | d) To run irqtop on Debian 8 you may need to install: 167 | 168 | # apt-get install ruby ruby-dev ncurses-dev 169 | # gem install curses 170 | 171 | z) If all fails create ticket at 172 | https://github.com/aabc/ipt-netflow/issues 173 | 174 | ** 5. After this point you should be able to load module and 175 | use -j NETFLOW target in your iptables. See next section. 176 | 177 | 178 | ===================== 179 | = Configure Options = 180 | ===================== 181 | 182 | Configure script allows to enable or disable optional features: 183 | 184 | --enable-natevents 185 | enables natevents (NEL) support, (this and option will require 186 | conntrack support to be enabled into kernel and conntack 187 | module (nf_conntrack) loaded before ipt_NETFLOW. Usually this is 188 | done automatically because of `depmod', but if you don't do `make 189 | install' you'll need to load nf_conntrack manually. 190 | Read below for explanation of natevents. 191 | 192 | --enable-sampler 193 | enables flow sampler. Read below for explanation of its configuration 194 | option. 195 | 196 | --enable-sampler=hash 197 | additionally enables 'hash' sampler. 198 | 199 | --disable-snmp-agent 200 | disables building net-snmp agent module, which is enabled by default. 201 | 202 | --enable-snmp-rules 203 | enables SNMP-index conversion rules. Read below for explanation 204 | of snmp-rules. 205 | 206 | --enable-macaddress 207 | enables exporting of src and dst MAC addresses for every flow 208 | in v9/IPFIX. Difference in any of MAC address will be accounted 209 | as different flow. I.e. MAC addresses will be part of flow key. 210 | 211 | --enable-vlan 212 | enables exporting of dot1q VLAN Ids and Priorities for every flow 213 | in v9/IPFIX. It supports outer and second dot1q tags if present. 214 | 215 | Any of two previous options will enable exporting of Ethernet Packet 216 | Type, ethernetType(256). 217 | 218 | --enable-direction 219 | enables exporting of flowDirection(61) Element for v9/IPFIX. 220 | 221 | Packets captured in PREROUTING and INPUT chains will be accounted as 222 | ingress flows(0), in OUTPUT and POSTROUTING as egress flows(1), and 223 | in FORWARD will have flowDirection set to undefined value 255. 224 | 225 | --enable-aggregation 226 | enables aggregation rules. Read below for explanation of aggregation. 227 | 228 | --disable-dkms 229 | disable creating dkms.conf and auto-install module into DKMS tree. 230 | 231 | --disable-dkms-install 232 | only disable auto-install into DKMS, but still create dkms.conf, in 233 | case you will want to install it manually. 234 | 235 | --enable-physdev 236 | Export ingressPhysicalInterface(252) and egressPhysicalInterface(253) 237 | (relevant for bridges) in V9 and IPFIX. If your collector does not 238 | support these Elements but you still need physdevs then use 239 | --enable-physdev-override, in that case physdevs will override normal 240 | interface numbers ingressInterface(10) and egressInterface(14). 241 | 242 | --enable-promisc 243 | Enables capturing of promiscuous packets into raw/PREROUTING chain. 244 | See README.promisc Solution 1 for usage details and example. 245 | 246 | --promisc-mpls 247 | Enables MPLS label stack decapsulation for promiscuous packets. (For 248 | IPv4 and IPv6 packets only). This also enables MPLS-aware NetFlow (v9 249 | and IPFIX), you may wish to specify with --promisc-mpls=n how much MPLS 250 | labels you want to be recorded and exported (default is 3, maximum is 251 | 10, set to 0 to not report anything). 252 | 253 | 254 | =========== 255 | = RUNNING = 256 | =========== 257 | 258 | 1. You can load module directly by insmod like this: 259 | 260 | # insmod ipt_NETFLOW.ko destination=127.0.0.1:2055 debug=1 261 | 262 | Or if properly installed (make install; depmod) by this: 263 | 264 | # modprobe ipt_NETFLOW destination=127.0.0.1:2055 265 | 266 | See, you may add options in insmod/modprobe command line, or add 267 | them in /etc/modprobe.conf or /etc/modprobe.d/ipt_NETFLOW.conf 268 | like thus: 269 | 270 | options ipt_NETFLOW destination=127.0.0.1:2055 protocol=9 natevents=1 271 | 272 | 2. Statistics is in /proc/net/stat/ipt_netflow 273 | Machine readable statistics is in /proc/net/stat/ipt_netflow_snmp 274 | To view boring slab statistics: grep ipt_netflow /proc/slabinfo 275 | Dump of all flows is in /proc/net/stat/ipt_netflow_flows 276 | 277 | 3. You can view parameters and control them via sysctl, example: 278 | 279 | # sysctl net.netflow 280 | # sysctl net.netflow.hashsize=32768 281 | 282 | Note: For after-reboot configuration I recommend to store module parameters 283 | in modprobe configs instead of storing them in /etc/sysctl.conf, as it's 284 | less clear when init process will apply sysctl.conf, before of after 285 | module's load. 286 | 287 | 4. Example of directing all IPv4 traffic into the module: 288 | 289 | # iptables -I FORWARD -j NETFLOW 290 | # iptables -I INPUT -j NETFLOW 291 | # iptables -I OUTPUT -j NETFLOW 292 | 293 | Note: It is preferable (because easier to understand) to _insert_ 294 | NETFLOW target at the top of the chain, otherwise not all traffic may 295 | reach NETFLOW if your iptables configuration is complicated and some 296 | other rule inadvertently consume the traffic (dropping or acepting before 297 | NETFLOW is reached). It's always good to test your configuration. 298 | Use iptables -L -nvx to check pkts/bytes counters on the rules. 299 | 300 | 5. If you want to account IPv6 traffic you should use protocol 9 or 10. 301 | Example of directing all IPv6 traffic into the module: 302 | 303 | # sysctl net.netflow.protocol=10 304 | # ip6tables -I FORWARD -j NETFLOW 305 | # ip6tables -I INPUT -j NETFLOW 306 | # ip6tables -I OUTPUT -j NETFLOW 307 | 308 | Note: First enable right version of protocol and after that add ip6tables 309 | rules, otherwise you will get errors in dmesg. 310 | 311 | 6. If you want to account NAT events (NEL): 312 | 313 | # sysctl net.netflow.natevents=1 314 | 315 | Note that natevents feature is completely independent from traffic accounting 316 | (it's using so called conntrack events), thus you don't need to set or change 317 | any iptables rules to use that. You may need to enable kernel config option 318 | CONFIG_NF_CONNTRACK_EVENTS though (if it isn't already enabled). 319 | For details on how they are exported for different protocol versions see 320 | below. 321 | 322 | 7. For SNMP support you will need to add this command into snmpd.conf to 323 | enable IPT-NETFLOW-MIB in SNMP agent: 324 | 325 | dlmod netflow /usr/lib/snmp/dlmod/snmp_NETFLOW.so 326 | 327 | Restart snmpd for changes to take effect. Don't forget to properly configure 328 | access control. Example simplest configuration may looks like (note that this 329 | is whole /etc/snmp/snmpd.conf): 330 | 331 | rocommunity public 127.0.0.1 332 | dlmod netflow /usr/lib/snmp/dlmod/snmp_NETFLOW.so 333 | 334 | Note, that this config will also allow _full_ read-only access to the whole 335 | linux MIB. To install IPT-NETFLOW-MIB locally, copy file IPT-NETFLOW-MIB.my 336 | into ~/.snmp/mibs/ 337 | 338 | * Detailed example of SNMP configuration is there: 339 | * https://github.com/aabc/ipt-netflow/wiki/Configuring-SNMP-access 340 | 341 | To check that MIB is installed well you may issue: 342 | 343 | $ snmptranslate -m IPT-NETFLOW-MIB -IR -Tp iptNetflowMIB 344 | 345 | This should output IPT-NETFLOW-MIB in tree form. 346 | 347 | To check that snmp agent is working well issue: 348 | 349 | $ snmpwalk -v 1 -c public 127.0.0.1 -m IPT-NETFLOW-MIB iptNetflowMIB 350 | 351 | Should output full MIB. If MIB is not installed try: 352 | 353 | $ snmpget -v 1 -c public 127.0.0.1 .1.3.6.1.4.1.37476.9000.10.1.1.1.1.0 354 | 355 | Which should output STRING: "ipt_NETFLOW". 356 | 357 | MIB provides access to very similar statistics that you have in 358 | /proc/net/stat/ipt_netflow, you can read description of objects in 359 | text file IPT-NETFLOW-MIB.my 360 | 361 | If you want to access to SNMP stat in machine readable form for your 362 | scripts there is file /proc/net/stat/ipt_netflow_snmp 363 | 364 | Note: Using of SNMP v2c or v3 is mandatory for most tables, because 365 | this MIB uses 64-bit counters (Counter64) which is not supported in old 366 | SNMP v1. You should understand that 32-bit counter will wrap on 10Gbit 367 | traffic in just 3.4 seconds! So, always pass option `-v2c' or `-v3' 368 | to net-snmp utils. Or, for example, configure option `defVersion 2c' 369 | in ~/.snmp/snmp.conf You can also have `defCommunity public' ov v3 370 | auth parameters (defSecurityName, defSecurityLevel, defPassphrase) 371 | set there (man snmp.conf). 372 | 373 | Examples for dumping typical IPT-NETFLOW-MIB objects: 374 | 375 | - Module info (similar to modinfo, SNMPv1 is ok for following two objects): 376 | 377 | $ snmpwalk -v 1 -c public 127.0.0.1 -m IPT-NETFLOW-MIB iptNetflowModule 378 | 379 | - Read-write sysctl-like parameters (yes, they are writable via snmpset, you 380 | may need to configure write access to snmpd, though): 381 | 382 | $ snmpwalk -v 1 -c public 127.0.0.1 -m IPT-NETFLOW-MIB iptNetflowSysctl 383 | 384 | - Global performance stat of the module (note -v2c, because rest of the 385 | objects require SNMP v2c or SNMP v3): 386 | 387 | $ snmpwalk -v2c -c public 127.0.0.1 -m IPT-NETFLOW-MIB iptNetflowTotals 388 | 389 | - Per-CPU (metering) and per-socket (exporting) statistics in table format: 390 | 391 | $ snmptable -v2c -c public 127.0.0.1 -m IPT-NETFLOW-MIB iptNetflowCpuTable 392 | $ snmptable -v2c -c public 127.0.0.1 -m IPT-NETFLOW-MIB iptNetflowSockTable 393 | 394 | 395 | =========== 396 | = OPTIONS = 397 | =========== 398 | 399 | Options can be passed as parameters to module or changed dynamically 400 | via sysctl net.netflow or IPT-NETFLOW-MIB::iptNetflowSysctl 401 | 402 | protocol=5 403 | - what version of NetFlow protocol to use. Default is 5. 404 | You can choose from 5, 9, or 10 (where 10 is IPFIX). If you plan 405 | to account IPv6 traffic you should use protocol 9 or 10 (IPFIX), 406 | because NetFlow v5 isn't compatible with IPv6. 407 | 408 | destination=127.0.0.1:2055 409 | - where to export netflow, to this ip address. Port is optional, default 410 | is 2055. You will see this connection in netstat like this: 411 | 412 | udp 0 0 127.0.0.1:32772 127.0.0.1:2055 ESTABLISHED 413 | 414 | destination=[2001:db8::1]:2055 415 | - export target using IPv6 address. Brackets are optional, but otherwise 416 | you should delimit port with 'p' or '#' character. 417 | 418 | destination=127.0.0.1:2055,192.0.0.1:2055 419 | - mirror flows to two (can be more) addresses, separate addresses 420 | with comma. 421 | 422 | destination=127.0.0.1:2055@127.0.0.2 423 | - bind socket to address (127.0.0.2). 424 | 425 | destination=127.0.0.1:2055%eth0 426 | - bind socket to interface (eth0). May be useful for multi-homed boxes. 427 | 428 | sampler=deterministic:123 429 | sampler=random:123 430 | sampler=hash:123 431 | - enables Flow Sampling. To disable set to the empty value or to `0'. 432 | Note, that this is flow sampling (as of RFC 7014), not packet 433 | sampling (PSAMP). 434 | 435 | There is three sampling modes: 436 | 437 | deterministic: select each N-th observed flow; in IPFIX this mode 438 | is called Systematic count-based Sampling; 439 | random: select randomly one out of N flows. 440 | hash: select hash-randomly one out of N flows. 441 | 442 | Number after colon is population size N, with valid values 2-16383. 443 | (This 16383 limit is for compatibility with NetFlow v5.) 444 | Using 'deterministic' and 'random' sampling will not reduce resource 445 | usage caused by the module, because flows are sampled late in exporting 446 | process. This will reduces amount of flows which go to the collector, 447 | thus, reducing load on the collector. 448 | On the other hand, using 'hash' sampling will reduce CPU and memory 449 | load caused by the module, because flows are discarded early in the 450 | processing chain. They are discarded almost like in random sampler, 451 | except that pseudo-random value is depend on the Flow Key hash for each 452 | packet. 453 | All required NetFlow/IPFIX information to signal use of sampling is 454 | also sent to the collector. 'Hash' sampling will be presented as 'random' 455 | sampling to the collector, because of their similarity. 456 | Note, that Flow Sampling is compatible with NetFlow v5, v9, and IPFIX. 457 | 458 | natevents=1 459 | - Collect and send NAT translation events as NetFlow Event Logging (NEL) 460 | for NetFlow v9/IPFIX, or as dummy flows compatible with NetFlow v5. 461 | Default is 0 (don't send). 462 | 463 | For NetFlow v5 protocol meaning of fields in dummy flows are such: 464 | Src IP, Src Port is Pre-nat source address. 465 | Dst IP, Dst Port is Post-nat destination address. 466 | - These two fields made equal to data flows caught in FORWARD chain. 467 | Nexthop, Src AS is Post-nat source address for SNAT. Or, 468 | Nexthop, Dst AS is Pre-nat destination address for DNAT. 469 | TCP Flags is SYN+SCK for start event, RST+FIN for stop event. 470 | Pkt/Traffic size is 0 (zero), so it won't interfere with accounting. 471 | 472 | Natevents are compilation disabled by default, to enable you will need to 473 | add --enable-natevents option to ./configure script. 474 | 475 | For technical description of NAT Events see: 476 | http://tools.ietf.org/html/draft-ietf-behave-ipfix-nat-logging-04 477 | 478 | inactive_timeout=15 479 | - export flow after it's inactive for 15 seconds. Default value is 15. 480 | 481 | active_timeout=1800 482 | - export flow after it's active for 1800 seconds (30 minutes). Default 483 | value is 1800. 484 | 485 | refresh-rate=20 486 | - for NetFlow v9 and IPFIX it's rate how frequently to re-send templates 487 | (per packets). You probably don't need to change default (which is 20). 488 | 489 | timeout-rate=30 490 | - for NetFlow v9 and IPFIX it's rate when to re-send old templates (in 491 | minutes). No need to change it. 492 | 493 | debug=0 494 | - debug level (none). 495 | 496 | sndbuf=number 497 | - size of output socket buffer in bytes. I recommend you to put higher 498 | value if you experience netflow packet drops (can be seen in statistics 499 | as 'sock: fail' number.) 500 | Default value is system default. 501 | 502 | hashsize=number 503 | - Hash table bucket size. Used for performance tuning. 504 | Abstractly speaking, it should be minimum two times bigger than flows 505 | you usually have, but not need to. 506 | Default is system memory dependent small enough value. 507 | 508 | maxflows=2000000 509 | - Maximum number of flows to account. It's here to prevent DOS attacks. 510 | After this limit is reached new flows will not be accounted. Default is 511 | 2000000, zero is unlimited. 512 | 513 | aggregation=string.. 514 | - Few aggregation rules (or some say they are rule.) 515 | 516 | Buffer for aggregation string 1024 bytes, and sysctl limit it 517 | to ~700 bytes, so don't write there a lot. 518 | Rules worked in definition order for each packet, so don't 519 | write them a lot again. 520 | Rules applied to both directions (dst and src). 521 | Rules tried until first match, but for netmask and port 522 | aggregations separately. 523 | Delimit them with commas. 524 | 525 | Rules are of two kinds: for netmask aggregation 526 | and port aggregation: 527 | 528 | a) Netmask aggregation example: 192.0.0.0/8=16 529 | Which mean to strip addresses matching subnet 192.0.0.0/8 to /16. 530 | 531 | b) Port aggregation example: 80-89=80 532 | Which mean to replace ports from 80 to 89 with 80. 533 | 534 | Full example: 535 | aggregation=192.0.0.0/8=16,10.0.0.0/8=16,80-89=80,3128=80 536 | 537 | Aggregation rules are enabled by default, if you feel you don't need them 538 | you may add --disable-aggregation to ./configure script. 539 | 540 | snmp-rules=string... 541 | - Few SNMP-index conversion rules similar to fproble-ulog. 542 | 543 | Quoting man fprobe-ulog: 544 | 545 | "Comma separated list of interface name to SNMP-index conversion 546 | rules. Each rule consists of interface base name and SNMP-index 547 | base separated by colon (e.g. ppp:200). Final SNMP-index is sum 548 | of corresponding SNMP-index base and interface number. 549 | In the above example SNMP-index of interface ppp11 is 211. 550 | 551 | If interface name did not fit to any of conversion rules then 552 | SNMP-index will be taken from kernel." 553 | 554 | This implementation isn't optimized for performance (no rule caching 555 | or hashing), but should be fast if rules list are short. 556 | 557 | Rules are parsed in order from first to last until first match. 558 | 559 | snmp-rules are compilation disabled by default, to enable you will need 560 | to add --enable-snmp option to ./configure script. 561 | 562 | scan-min=1 563 | - Minimal interval between flow export scans. Sometimes could be useful 564 | to reduce load on exporting CPU by increasing this interval. Value are 565 | in kernel jiffies units (which is x/HZ seconds). 566 | 567 | promisc=1 568 | - Enables promisc hack. See README.promisc Solution 1 for details. 569 | 570 | exportcpu=number 571 | - Lock exporter to single CPU. This may be useful to fine control CPU 572 | load. Common use case: with smp_affinity and RSS you spread packet 573 | processing to all CPUs except one, and lock it to the exporter. While 574 | exporter CPU load generally is not high, for someone it may be not 575 | desirable to combine it with packet processing on very highly loaded 576 | routers. 577 | 578 | This option could be changed at runtime with: 579 | 580 | # echo number > /sys/module/ipt_NETFLOW/parameters/exportcpu 581 | 582 | engine_id=number 583 | - Observation Domain ID (on IPFIX, Source Id on NetFlow v9, or Engine Id 584 | on NetFlow v5) value to be exported. This may help your collector to 585 | distinguish between multiple exporters. On Netflow v9 and IPFIX this 586 | value is 32-bit on NetFlow v5 only 8 low bits are significant. 587 | Default value is 0. 588 | 589 | This option could be changed at runtime with: 590 | 591 | # echo number > /sys/module/ipt_NETFLOW/parameters/engine_id 592 | 593 | 594 | ==================== 595 | = HOW TO READ STAT = 596 | ==================== 597 | 598 | Statistics is your friend to fine tune and understand netflow module 599 | performance. 600 | 601 | To see stat in human readable form: 602 | # cat /proc/net/stat/ipt_netflow 603 | 604 | How to interpret the data: 605 | 606 | > ipt_NETFLOW version v1.8-122-gfae9d59-dirty, srcversion 6141961152BE0DFA6A21EF4; aggr mac vlan 607 | 608 | This line helps to identify actual source that your module is build on. 609 | Please always supply it in all bug reports. 610 | 611 | v1.8-122: 1.8 is release, 122 is commit number after release; 612 | -gfae9d59: fae9d59 is short git commit id; 613 | -dirty: if present, meaning that git detected that sources are changed since 614 | last git commit, you may wish to do `git diff' to view changes; 615 | srcversion 6141961152BE0DFA6A21EF4: binary version of module, you can 616 | compare this with data from `modinfo ./ipt_NETFLOW.ko' to identify 617 | actual binary loaded; 618 | aggr mac vlan: tags to identify compile time options that are enabled. 619 | 620 | > Protocol version 10 (ipfix), refresh-rate 20, timeout-rate 30, (templates 2, active 2). Timeouts: active 5, inactive 15. Maxflows 2000000 621 | 622 | Protocol version currently in use. Refresh-rate and timeout-rate 623 | for v9 and IPFIX. Total templates generated and currently active. 624 | Timeout: active X: how much seconds to wait before exporting active flow. 625 | - same as sysctl net.netflow.active_timeout variable. 626 | inactive X: how much seconds to wait before exporting inactive flow. 627 | - same as sysctl net.netflow.inactive_timeout variable. 628 | Maxflows 2000000: maxflows limit. 629 | - all flows above maxflows limit must be dropped. 630 | - you can control maxflows limit by sysctl net.netflow.maxflows variable. 631 | 632 | > Promisc hack is disabled (observed 0 packets, discarded 0). 633 | 634 | observed n: To see that promisc hack is really working. 635 | 636 | > Natevents disabled, count start 0, stop 0. 637 | 638 | - Natevents mode disabled or enabled, and how much start or stop events 639 | are reported. 640 | 641 | > Flows: active 5187 (peak 83905 reached 0d0h1m ago), mem 283K, worker delay 100/1000 (37 ms, 0 us, 4:0 0 [3]). 642 | 643 | active X: currently active flows in memory cache. 644 | - for optimum CPU performance it is recommended to set hash table size to 645 | at least twice of average of this value, or higher. 646 | peak X reached Y ago: peak value of active flows. 647 | mem XK: how much kilobytes of memory currently taken by active flows. 648 | - one active flow taking 56 bytes of memory. 649 | - there is system limit on cache size too. 650 | worker delay X/HZ: how frequently exporter scan flows table per second. 651 | Rest is boring debug info. 652 | 653 | > Hash: size 8192 (mem 32K), metric 1.00, [1.00, 1.00, 1.00]. InHash: 1420 pkt, 364 K, InPDU 28, 6716. 654 | 655 | Hash: size X: current hash size/limit. 656 | - you can control this by sysctl net.netflow.hashsize variable. 657 | - increasing this value can significantly reduce CPU load. 658 | - default value is not optimal for performance. 659 | - optimal value is twice of average of active flows. 660 | mem XK: how much memory occupied by hash table. 661 | - hash table is fixed size by nature, taking 4 bytes per entry. 662 | metric X, [X, X, X]: how optimal is your hash table being used. 663 | - lesser value mean more optimal hash table use, min is 1.0. 664 | - last three numbers in squares is moving average (EWMA) of hash table 665 | access divided by match rate (searches / matches) for 4sec, and 1, 5, and 666 | 15 minutes. Sort of hash table load average. First value is instantaneous. 667 | You can try to increase hashsize if averages more than 1 (increase 668 | certainly if >= 2). 669 | InHash: X pkt, X K: how much traffic accounted for flows in the hash table. 670 | InPDU X, X: how much traffic in flows preparing to be exported. 671 | 672 | > Rate: 202448 bits/sec, 83 packets/sec; 1 min: 668463 bps, 930 pps; 5 min: 329039 bps, 483 pps 673 | 674 | - Module throughput values for 1 second, 1 minute, and 5 minutes. 675 | 676 | > cpu# pps; , traffic: , drop: 677 | > cpu0 123; 980540 10473 180600 [1.03], 0 0 0 0, traffic: 188765, 14 MB, drop: 27863, 1142 K 678 | 679 | cpu#: this is Total and per CPU statistics for: 680 | pps: packets per second on this CPU. It's useful to debug load imbalance. 681 | : internal stat for: 682 | search found new: hash table searched, found, and not found counters. 683 | [metric]: one minute (ewma) average hash metric per cpu. 684 | trunc: how much truncated packets are ignored 685 | - for example if packets don't have valid IP header. 686 | - it's also accounted in drop packets counter, but not in drop bytes. 687 | frag: how much fragmented packets have seen. 688 | - kernel defragments INPUT/OUTPUT chains for us if nf_defrag_ipv[46] 689 | module is loaded. 690 | - these packets are not ignored but not reassembled either, so: 691 | - if there is no enough data in fragment (ex. tcp ports) it is considered 692 | to be zero. 693 | alloc: how much cache memory allocations are failed. 694 | - packets ignored and accounted in traffic drop stat. 695 | - probably increase system memory if this ever happen. 696 | maxflows: how much packets ignored on maxflows (maximum active flows reached). 697 | - packets ignored and accounted in traffic drop stat. 698 | - you can control maxflows limit by sysctl net.netflow.maxflows variable. 699 | 700 | traffic: : how much traffic is accounted. 701 | pkt, bytes: sum of packets/megabytes accounted by module. 702 | - flows that failed to be exported (on socket error) is accounted here too. 703 | 704 | drop: : how much of traffic is not accounted. 705 | pkt, bytes: sum of packets/kilobytes that are dropped by metering process. 706 | - reasons these drops are accounted here: 707 | truncated/fragmented packets, 708 | packet is for new flow but failed to allocate memory for it, 709 | packet is for new flow but maxflows is already reached. 710 | Traffic lost due to socket errors is not accounted here. Look below 711 | about export and socket errors. 712 | 713 | > Export: Rate 0 bytes/s; Total 2 pkts, 0 MB, 18 flows; Errors 0 pkts; Traffic lost 0 pkts, 0 Kbytes, 0 flows. 714 | 715 | Rate X bytes/s: traffic rate generated by exporter itself. 716 | Total X pkts, X MB: total amount of traffic generated by exporter. 717 | X flows: how much data flows are exported. 718 | Errors X pkts: how much packets not sent due to socket errors. 719 | Traffic lost 0 pkts, 0 Kbytes, 0 flows: how much metered traffic is lost 720 | due to socket errors. 721 | Note that `cberr' errors are not accounted here due to their asynchronous 722 | nature. Read below about `cberr' errors. 723 | 724 | > sock0: 10.0.0.2:2055 unconnected (1 attempts). 725 | 726 | If socket is unconnected (for example if module loaded before interfaces is 727 | up) it shows now much connection attempts was failed. It will try to connect 728 | until success. 729 | 730 | > sock0: 10.0.0.2:2055, sndbuf 106496, filled 0, peak 106848; err: sndbuf reached 928, connect 0, cberr 0, other 0 731 | 732 | sockX: per destination stats for: 733 | X.X.X.X:Y: destination ip address and port. 734 | - controlled by sysctl net.netflow.destination variable. 735 | sndbuf X: how much data socket can hold in buffers. 736 | - controlled by sysctl net.netflow.sndbuf variable. 737 | - if you have packet drops due to sndbuf reached (error -11) increase this 738 | value. 739 | filled X: how much data in socket buffers right now. 740 | peak X: peak value of how much data in socket buffers was. 741 | - you will be interested to keep it below sndbuf value. 742 | err: how much packets are dropped due to errors. 743 | - all flows from them will be accounted in drop stat. 744 | sndbuf reached X: how much packets dropped due to sndbuf being too small 745 | (error -11). 746 | connect X: how much connection attempts was failed. 747 | cberr X: how much connection refused ICMP errors we got from export target. 748 | - probably you are not launched collector software on destination, 749 | - or specified wrong destination address. 750 | - flows lost in this fashion is not possible to account in drop stat. 751 | - these are ICMP errors, and would look like this in tcpdump: 752 | 05:04:09.281247 IP alice.19440 > bob.2055: UDP, length 120 753 | 05:04:09.281405 IP bob > alice: ICMP bob udp port 2055 unreachable, length 156 754 | other X: dropped due to other possible errors. 755 | 756 | > aggr0: ... 757 | aggrX: aggregation rulesets. 758 | - controlled by sysctl net.netflow.aggregation variable. 759 | 760 | 761 | ========================== 762 | = NetFlow considerations = 763 | ========================== 764 | 765 | List of all IPFIX Elements http://www.iana.org/assignments/ipfix/ipfix.xhtml 766 | 767 | Flow Keys are Elements that distinguish flows. Quoting RFC: "If a Flow 768 | Record for a specific Flow Key value already exists, the Flow Record is 769 | updated; otherwise, a new Flow Record is created." 770 | 771 | In this implementation following Elements are treated as Flow Keys: 772 | 773 | IPv4 source address: sourceIPv4Address(8), 774 | IPv6 source address: sourceIPv6Address(27), 775 | IPv4 destination address: destinationIPv4Address(12), 776 | IPv6 destination address: destinationIPv6Address(28), 777 | TCP/UDP source port: sourceTransportPort(7), 778 | TCP/UDP destination port: destinationTransportPort(11), 779 | input interface: ingressInterface(10), 780 | IP protocol: protocolIdentifier(4), 781 | IP TOS: ipClassOfService(5), 782 | and address family (IP or IPv6). 783 | 784 | Additional Flow Keys if VLAN exporting is enabled: 785 | 786 | First (outer) dot1q VLAN tag: dot1qVlanId(243) and 787 | dot1qPriority(244) for IPFIX, 788 | or vlanId(243) for NetFlow v9. 789 | Second (customer) dot1q VLAN tag: dot1qCustomerVlanId(245) 790 | and dot1qCustomerPriority(246). 791 | 792 | Additional Flow Keys if MAC address exporting is enabled: 793 | 794 | Destination MAC address: destinationMacAddress(80), 795 | Source MAC address: sourceMacAddress(56). 796 | 797 | Additional Flow Keys if MPLS-aware NetFlow is enabled: 798 | 799 | Captured MPLS stack is fully treated as flow key (including TTL values), 800 | which is Elements from mplsTopLabelStackSection(70) to 801 | mplsLabelStackSection10(79), and, if present, mplsTopLabelTTL(200). 802 | 803 | 804 | Other Elements are not Flow Keys. Note that outer interface, which is 805 | egressInterface(14), is not regarded as Flow Key. Quoting RFC 7012: "For 806 | Information Elements ... for which the value may change from packet to packet 807 | within a single Flow, the exported value of an Information Element is by 808 | default determined by the first packet observed for the corresponding Flow". 809 | 810 | Note that NetFlow and IPFIX modes of operation may have slightly different 811 | Elements being used and different statistics sent via Options Templates. 812 | 813 | 814 | ========= 815 | = VOILA = 816 | ========= 817 | -------------------------------------------------------------------------------- /README.promisc: -------------------------------------------------------------------------------- 1 | Hello, 2 | 3 | If you wish to account with ipt-netflow module traffic mirrored on switch you may follow 4 | one of these examples: 5 | 6 | 7 | Solution 1: Promisc-hack module option. [2014] 8 | Solution 2: General kernel patch. [2008] 9 | Solution 3: Alternative w/o kernel patch, using bridges. [2010] 10 | 11 | 12 | ************** 13 | * Solution 1 * 14 | ************** 15 | 16 | No kernel patching is need anymore! (As in easy.) 17 | 18 | Compile module with `./configure --enable-promisc' option. This will enable 19 | `promisc=' module parameter and sysctl parameter `net.netflow.promisc'. 20 | Set any of these to `1' to enable promisc hack, you will see dmesg message 21 | that it's enabled, set to `0' to disable (default). 22 | 23 | This option turned on will pass promisc traffic into `PREROUTING' chain 24 | of `raw' table (same as with promisc patches). Briefly it's like this: 25 | 26 | # cd ipt-netflow/ 27 | # ./configure --enable-promisc 28 | # make all install 29 | # iptables -A PREROUTING -t raw -i eth2 -j NETFLOW 30 | # sysctl net.netflow.promisc=1 31 | # ifconfig eth2 promisc 32 | # grep Promisc /proc/net/stat/ipt_netflow 33 | 34 | Now you should be able to see promisc observed packets count increasing. 35 | 36 | Note, that enabling module's parameter promisc=1 will not enable promiscuous 37 | mode on network cards, these are completely different things. This option will 38 | let iptables to see promisc traffic. That traffic will not be routed anywhere 39 | and discarded just after passing PREROUTING chain. 40 | 41 | Do not enable this option if you have kernel already patched with promisc 42 | patch, as this may cause double accounting. Just keep it disabled or remove 43 | the patch. Promisc patching is completely custom and non-standard, so if you 44 | did not apply it - you are most probably safe to use promisc option. But, if 45 | in doubt - measure if module seeing traffic in raw/PREROUTING, if it isn't - you 46 | don't have the patch applied and certainly safe to use the option. 47 | 48 | 49 | 50 | ************** 51 | * Solution 2 * 52 | ************** 53 | 54 | 1. Patch your kernel with `raw_promisc.patch' to enable raw table to see promisc traffic. 55 | 56 | # cd /usr/src/linux 57 | # patch -p1 < ~/ipt_netflow/raw_promisc.patch 58 | 59 | Then recompile and reinstall patched kernel. 60 | 61 | 2. For example you mirroring traffic on your Cisco switch to 47th vlan: 62 | 63 | # interface FastEthernet0/32 64 | # description this port with vlan 47 65 | # switchport trunk encapsulation dot1q 66 | # switchport mode trunk 67 | # ! 68 | # interface FastEthernet0/33 69 | # port monitor FastEthernet0/32 70 | # ! 71 | 72 | 3. Enable promisc mode on interface to actually see the packets: 73 | 74 | # /sbin/ifconfig eth1 promisc 75 | 76 | 4. Configure vlan on your linux box: 77 | 78 | # /sbin/vconfig add eth1 47 79 | # /sbin/ifconfig eth1.47 up 80 | 81 | 5. Compile module: 82 | 83 | # make clean all install 84 | 85 | 6. Load ipt_netflow module: 86 | 87 | # /sbin/modprobe ipt_NETFLOW hashsize=160000 destination=127.0.0.1:9800 88 | 89 | 7. Direct all packets from 47th vlan to ipt_netflow module: 90 | 91 | # /sbin/iptables -A PREROUTING -t raw -i eth1.47 -j NETFLOW 92 | 93 | Voila. 94 | 95 | ps. For Debian Squeeze instructions look at raw_promisc_debian_squeeze6.patch 96 | 97 | 98 | 99 | ************** 100 | * Solution 3 * 101 | ************** 102 | 103 | By Anonymous. 104 | 105 | > raw promisc hack is not needed 106 | > there is a more elegant way to capture port mirrored traffic: 107 | > 108 | > 1. create a bridge of eth0 and dummy0 109 | > 2. put eth0 to promisc 110 | > 3. add a "-i br0 -j NETFLOW" rule to FORWARD (possibly also -j DROP after that) 111 | > 112 | > ...for some reason it works when ipt_netflow is attached to a bridge, but 113 | > requires the promisc hack when attached to a real promisc interface. 114 | 115 | Sometimes you may need to run: 116 | 117 | # brctl setageing br0 0 118 | 119 | for this scheme to work. 120 | 121 | -------------------------------------------------------------------------------- /compat.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only 2 | * 3 | * This code is derived from the Linux Kernel sources intended 4 | * to maintain compatibility with different Kernel versions. 5 | * Copyright of original source is of respective Linux Kernel authors. 6 | */ 7 | 8 | #ifndef COMPAT_NETFLOW_H 9 | #define COMPAT_NETFLOW_H 10 | #include "compat_def.h" 11 | 12 | #ifndef NIPQUAD 13 | # define NIPQUAD(addr) \ 14 | ((unsigned char *)&addr)[0], \ 15 | ((unsigned char *)&addr)[1], \ 16 | ((unsigned char *)&addr)[2], \ 17 | ((unsigned char *)&addr)[3] 18 | #endif 19 | #ifndef HIPQUAD 20 | # if defined(__LITTLE_ENDIAN) 21 | # define HIPQUAD(addr) \ 22 | ((unsigned char *)&addr)[3], \ 23 | ((unsigned char *)&addr)[2], \ 24 | ((unsigned char *)&addr)[1], \ 25 | ((unsigned char *)&addr)[0] 26 | # elif defined(__BIG_ENDIAN) 27 | # define HIPQUAD NIPQUAD 28 | # else 29 | # error "Please fix asm/byteorder.h" 30 | # endif /* __LITTLE_ENDIAN */ 31 | #endif 32 | 33 | #ifndef IPT_CONTINUE 34 | # define IPT_CONTINUE XT_CONTINUE 35 | # define ipt_target xt_target 36 | #endif 37 | 38 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) 39 | union nf_inet_addr { 40 | __be32 ip; 41 | __be32 ip6[4]; 42 | struct in_addr in; 43 | struct in6_addr in6; 44 | }; 45 | #endif 46 | 47 | #ifndef list_first_entry 48 | #define list_first_entry(ptr, type, member) \ 49 | list_entry((ptr)->next, type, member) 50 | #endif 51 | 52 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) 53 | # define INIT_NET(x) x 54 | #else 55 | # define INIT_NET(x) init_net.x 56 | #endif 57 | 58 | #ifndef ETH_P_8021AD 59 | # define ETH_P_8021AD 0x88A8 /* 802.1ad Service VLAN */ 60 | #endif 61 | 62 | #ifndef ETH_P_QINQ1 63 | # define ETH_P_QINQ1 0x9100 /* deprecated QinQ VLAN */ 64 | # define ETH_P_QINQ2 0x9200 /* deprecated QinQ VLAN */ 65 | # define ETH_P_QINQ3 0x9300 /* deprecated QinQ VLAN */ 66 | #endif 67 | 68 | #ifndef IPPROTO_MH 69 | # define IPPROTO_MH 135 70 | #endif 71 | 72 | #ifdef CONFIG_SYSCTL 73 | # if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32) 74 | # define BEFORE2632(x,y) x,y 75 | # else /* since 2.6.32 */ 76 | # define BEFORE2632(x,y) 77 | # endif 78 | 79 | # if LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0) 80 | # define ctl_table struct ctl_table 81 | # endif 82 | 83 | # ifndef HAVE_GRSECURITY_H 84 | # define ctl_table_no_const ctl_table 85 | # endif 86 | #endif 87 | 88 | #if LINUX_VERSION_CODE < KERNEL_VERSION(3,9,0) 89 | # define compat_hlist_for_each_entry hlist_for_each_entry 90 | # define compat_hlist_for_each_entry_safe hlist_for_each_entry_safe 91 | #else /* since 3.9.0 */ 92 | # define compat_hlist_for_each_entry(a,pos,c,d) hlist_for_each_entry(a,c,d) 93 | # define compat_hlist_for_each_entry_safe(a,pos,c,d,e) hlist_for_each_entry_safe(a,c,d,e) 94 | #endif 95 | 96 | #ifndef WARN_ONCE 97 | #define WARN_ONCE(x,fmt...) ({ if (x) printk(KERN_WARNING fmt); }) 98 | #endif 99 | 100 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) 101 | # define IPPROTO_UDPLITE 136 102 | #endif 103 | 104 | #ifndef time_is_before_jiffies 105 | # define time_is_before_jiffies(a) time_after(jiffies, a) 106 | #endif 107 | #ifndef time_is_after_jiffies 108 | # define time_is_after_jiffies(a) time_before(jiffies, a) 109 | #endif 110 | 111 | #if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0) 112 | # if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) 113 | # define prandom_u32 get_random_int 114 | # elif LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0) 115 | # define prandom_u32 random32 116 | #endif 117 | #define prandom_u32_max compat_prandom_u32_max 118 | static inline u32 prandom_u32_max(u32 ep_ro) 119 | { 120 | return (u32)(((u64) prandom_u32() * ep_ro) >> 32); 121 | } 122 | #endif 123 | 124 | #ifndef min_not_zero 125 | # define min_not_zero(x, y) ({ \ 126 | typeof(x) __x = (x); \ 127 | typeof(y) __y = (y); \ 128 | __x == 0 ? __y : ((__y == 0) ? __x : min(__x, __y)); }) 129 | #endif 130 | 131 | #if LINUX_VERSION_CODE < KERNEL_VERSION(3,2,0) 132 | static int __ethtool_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) 133 | { 134 | ASSERT_RTNL(); 135 | 136 | if (!dev->ethtool_ops->get_settings) 137 | return -EOPNOTSUPP; 138 | 139 | memset(cmd, 0, sizeof(struct ethtool_cmd)); 140 | cmd->cmd = ETHTOOL_GSET; 141 | return dev->ethtool_ops->get_settings(dev, cmd); 142 | } 143 | #endif 144 | 145 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) 146 | # define ethtool_cmd_speed(x) (x)->speed 147 | #endif 148 | 149 | #ifndef ARPHRD_PHONET 150 | # define ARPHRD_PHONET 820 151 | # define ARPHRD_PHONET_PIPE 821 152 | #endif 153 | #ifndef ARPHRD_IEEE802154 154 | # define ARPHRD_IEEE802154 804 155 | #endif 156 | 157 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) 158 | # define for_each_netdev_ns(net, dev) for (dev = dev_base; dev; dev = dev->next) 159 | #elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) 160 | # define for_each_netdev_ns(net, d) for_each_netdev(d) 161 | #else 162 | # define for_each_netdev_ns(net, d) for_each_netdev(net, d) 163 | #endif 164 | 165 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) 166 | # define CHECK_FAIL 0 167 | # define CHECK_OK 1 168 | #else 169 | # define CHECK_FAIL -EINVAL 170 | # define CHECK_OK 0 171 | #endif 172 | 173 | #ifndef NF_IP_LOCAL_IN /* 2.6.25 */ 174 | # define NF_IP_PRE_ROUTING NF_INET_PRE_ROUTING 175 | # define NF_IP_LOCAL_IN NF_INET_LOCAL_IN 176 | # define NF_IP_FORWARD NF_INET_FORWARD 177 | # define NF_IP_LOCAL_OUT NF_INET_LOCAL_OUT 178 | # define NF_IP_POST_ROUTING NF_INET_POST_ROUTING 179 | #endif 180 | 181 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) 182 | /* net/netfilter/x_tables.c */ 183 | static void xt_unregister_targets(struct xt_target *target, unsigned int n) 184 | { 185 | unsigned int i; 186 | 187 | for (i = 0; i < n; i++) 188 | xt_unregister_target(&target[i]); 189 | } 190 | static int xt_register_targets(struct xt_target *target, unsigned int n) 191 | { 192 | unsigned int i; 193 | 194 | int err = 0; 195 | for (i = 0; i < n; i++) 196 | if ((err = xt_register_target(&target[i]))) 197 | goto err; 198 | return err; 199 | err: 200 | if (i > 0) 201 | xt_unregister_targets(target, i); 202 | return err; 203 | } 204 | #endif 205 | 206 | #ifdef HAVE_TOTALRAM_PAGES 207 | #define num_physpages totalram_pages() 208 | #elif defined HAVE_TOTALRAM_PAGES_REF 209 | #define num_physpages totalram_pages 210 | #endif 211 | 212 | #ifndef HAVE_TIMEVAL 213 | /* timeval is only used internally, so we can use anything for it. */ 214 | struct timeval { 215 | long tv_sec; 216 | long tv_usec; /* microseconds */ 217 | }; 218 | 219 | unsigned long timeval_to_jiffies(const struct timeval *tv) 220 | { 221 | return timespec64_to_jiffies(&(struct timespec64){ 222 | tv->tv_sec, 223 | tv->tv_usec * NSEC_PER_USEC 224 | }); 225 | } 226 | #endif 227 | 228 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) 229 | # ifdef ktime_to_timeval 230 | /* ktime_to_timeval is defined on 64bit and inline on 32bit cpu */ 231 | /* when it's defined it calls ns_to_timeval, which is not exported */ 232 | struct timeval portable_ns_to_timeval(const s64 nsec) 233 | { 234 | struct timespec ts = ns_to_timespec(nsec); 235 | struct timeval tv; 236 | 237 | tv.tv_sec = ts.tv_sec; 238 | tv.tv_usec = (suseconds_t) ts.tv_nsec / 1000; 239 | 240 | return tv; 241 | } 242 | # define ns_to_timeval portable_ns_to_timeval 243 | # endif 244 | 245 | static inline s64 portable_ktime_to_ms(const ktime_t kt) 246 | { 247 | struct timeval tv = ktime_to_timeval(kt); 248 | return (s64) tv.tv_sec * MSEC_PER_SEC + tv.tv_usec / USEC_PER_MSEC; 249 | } 250 | # define ktime_to_ms portable_ktime_to_ms 251 | #endif /* before 2.6.35 */ 252 | 253 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) 254 | static inline s64 portable_ktime_to_us(const ktime_t kt) 255 | { 256 | struct timeval tv = ktime_to_timeval(kt); 257 | return (s64) tv.tv_sec * USEC_PER_SEC + tv.tv_usec; 258 | } 259 | #define ktime_to_us portable_ktime_to_us 260 | #endif 261 | 262 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) 263 | static inline void put_unaligned_be16(u16 val, void *p) 264 | { 265 | put_unaligned(cpu_to_be16(val), (__be16 *)p); 266 | } 267 | static inline void put_unaligned_be32(u32 val, void *p) 268 | { 269 | put_unaligned(cpu_to_be32(val), (__be32 *)p); 270 | } 271 | static inline void put_unaligned_be64(u64 val, void *p) 272 | { 273 | put_unaligned(cpu_to_be64(val), (__be64 *)p); 274 | } 275 | #endif 276 | 277 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,24) && !defined(RHEL_MAJOR) 278 | static void *__seq_open_private(struct file *f, struct seq_operations *ops, 279 | int psize) 280 | { 281 | int rc; 282 | void *private; 283 | struct seq_file *seq; 284 | 285 | private = kzalloc(psize, GFP_KERNEL); 286 | if (private == NULL) 287 | goto out; 288 | 289 | rc = seq_open(f, ops); 290 | if (rc < 0) 291 | goto out_free; 292 | 293 | seq = f->private_data; 294 | seq->private = private; 295 | return private; 296 | 297 | out_free: 298 | kfree(private); 299 | out: 300 | return NULL; 301 | } 302 | #endif 303 | 304 | /* disappeared in v3.19 */ 305 | #ifndef __get_cpu_var 306 | #define __get_cpu_var(var) (*this_cpu_ptr(&(var))) 307 | #endif 308 | 309 | #ifndef MPLS_HLEN 310 | #define MPLS_HLEN 4 311 | static inline int eth_p_mpls(__be16 eth_type) 312 | { 313 | return eth_type == htons(ETH_P_MPLS_UC) || 314 | eth_type == htons(ETH_P_MPLS_MC); 315 | } 316 | #endif 317 | #ifndef MPLS_LS_S_MASK 318 | struct mpls_label { 319 | __be32 entry; 320 | }; 321 | #define MPLS_LS_S_MASK 0x00000100 322 | 323 | #endif 324 | 325 | /* sockaddr comparison functions is from fs/nfs/client.c */ 326 | static int sockaddr_match_ipaddr6(const struct sockaddr *sa1, const struct sockaddr *sa2) 327 | { 328 | const struct sockaddr_in6 *sin1 = (const struct sockaddr_in6 *)sa1; 329 | const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)sa2; 330 | 331 | if (!ipv6_addr_equal(&sin1->sin6_addr, &sin2->sin6_addr)) 332 | return 0; 333 | #if 0 334 | else if (ipv6_addr_type(&sin1->sin6_addr) & IPV6_ADDR_LINKLOCAL) 335 | return sin1->sin6_scope_id == sin2->sin6_scope_id; 336 | #endif 337 | return 1; 338 | } 339 | 340 | static int sockaddr_match_ipaddr4(const struct sockaddr *sa1, const struct sockaddr *sa2) 341 | { 342 | const struct sockaddr_in *sin1 = (const struct sockaddr_in *)sa1; 343 | const struct sockaddr_in *sin2 = (const struct sockaddr_in *)sa2; 344 | 345 | return sin1->sin_addr.s_addr == sin2->sin_addr.s_addr; 346 | } 347 | 348 | static int sockaddr_cmp_ip6(const struct sockaddr *sa1, const struct sockaddr *sa2) 349 | { 350 | const struct sockaddr_in6 *sin1 = (const struct sockaddr_in6 *)sa1; 351 | const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)sa2; 352 | 353 | return sockaddr_match_ipaddr6(sa1, sa2) && 354 | (sin1->sin6_port == sin2->sin6_port); 355 | } 356 | 357 | static int sockaddr_cmp_ip4(const struct sockaddr *sa1, const struct sockaddr *sa2) 358 | { 359 | const struct sockaddr_in *sin1 = (const struct sockaddr_in *)sa1; 360 | const struct sockaddr_in *sin2 = (const struct sockaddr_in *)sa2; 361 | 362 | return sockaddr_match_ipaddr4(sa1, sa2) && 363 | (sin1->sin_port == sin2->sin_port); 364 | } 365 | 366 | static int sockaddr_cmp(const struct sockaddr_storage *sa1, const struct sockaddr_storage *sa2) 367 | { 368 | const struct sockaddr *s1 = (const struct sockaddr *)sa1; 369 | const struct sockaddr *s2 = (const struct sockaddr *)sa2; 370 | 371 | if (sa1->ss_family != sa2->ss_family) 372 | return 0; 373 | 374 | switch (sa1->ss_family) { 375 | case AF_INET: 376 | return sockaddr_cmp_ip4(s1, s2); 377 | case AF_INET6: 378 | return sockaddr_cmp_ip6(s1, s2); 379 | } 380 | return 0; 381 | } 382 | 383 | #ifndef IN6PTON_XDIGIT 384 | #define hex_to_bin compat_hex_to_bin 385 | /* lib/hexdump.c */ 386 | int hex_to_bin(char ch) 387 | { 388 | if ((ch >= '0') && (ch <= '9')) 389 | return ch - '0'; 390 | ch = tolower(ch); 391 | if ((ch >= 'a') && (ch <= 'f')) 392 | return ch - 'a' + 10; 393 | return -1; 394 | } 395 | 396 | /* net/core/utils.c */ 397 | #define IN6PTON_XDIGIT 0x00010000 398 | #define IN6PTON_DIGIT 0x00020000 399 | #define IN6PTON_COLON_MASK 0x00700000 400 | #define IN6PTON_COLON_1 0x00100000 /* single : requested */ 401 | #define IN6PTON_COLON_2 0x00200000 /* second : requested */ 402 | #define IN6PTON_COLON_1_2 0x00400000 /* :: requested */ 403 | #define IN6PTON_DOT 0x00800000 /* . */ 404 | #define IN6PTON_DELIM 0x10000000 405 | #define IN6PTON_NULL 0x20000000 /* first/tail */ 406 | #define IN6PTON_UNKNOWN 0x40000000 407 | 408 | static inline int xdigit2bin(char c, int delim) 409 | { 410 | int val; 411 | 412 | if (c == delim || c == '\0') 413 | return IN6PTON_DELIM; 414 | if (c == ':') 415 | return IN6PTON_COLON_MASK; 416 | if (c == '.') 417 | return IN6PTON_DOT; 418 | 419 | val = hex_to_bin(c); 420 | if (val >= 0) 421 | return val | IN6PTON_XDIGIT | (val < 10 ? IN6PTON_DIGIT : 0); 422 | 423 | if (delim == -1) 424 | return IN6PTON_DELIM; 425 | return IN6PTON_UNKNOWN; 426 | } 427 | 428 | int in4_pton(const char *src, int srclen, 429 | u8 *dst, 430 | int delim, const char **end) 431 | { 432 | const char *s; 433 | u8 *d; 434 | u8 dbuf[4]; 435 | int ret = 0; 436 | int i; 437 | int w = 0; 438 | 439 | if (srclen < 0) 440 | srclen = strlen(src); 441 | s = src; 442 | d = dbuf; 443 | i = 0; 444 | while(1) { 445 | int c; 446 | c = xdigit2bin(srclen > 0 ? *s : '\0', delim); 447 | if (!(c & (IN6PTON_DIGIT | IN6PTON_DOT | IN6PTON_DELIM | IN6PTON_COLON_MASK))) { 448 | goto out; 449 | } 450 | if (c & (IN6PTON_DOT | IN6PTON_DELIM | IN6PTON_COLON_MASK)) { 451 | if (w == 0) 452 | goto out; 453 | *d++ = w & 0xff; 454 | w = 0; 455 | i++; 456 | if (c & (IN6PTON_DELIM | IN6PTON_COLON_MASK)) { 457 | if (i != 4) 458 | goto out; 459 | break; 460 | } 461 | goto cont; 462 | } 463 | w = (w * 10) + c; 464 | if ((w & 0xffff) > 255) { 465 | goto out; 466 | } 467 | cont: 468 | if (i >= 4) 469 | goto out; 470 | s++; 471 | srclen--; 472 | } 473 | ret = 1; 474 | memcpy(dst, dbuf, sizeof(dbuf)); 475 | out: 476 | if (end) 477 | *end = s; 478 | return ret; 479 | } 480 | 481 | int in6_pton(const char *src, int srclen, 482 | u8 *dst, 483 | int delim, const char **end) 484 | { 485 | const char *s, *tok = NULL; 486 | u8 *d, *dc = NULL; 487 | u8 dbuf[16]; 488 | int ret = 0; 489 | int i; 490 | int state = IN6PTON_COLON_1_2 | IN6PTON_XDIGIT | IN6PTON_NULL; 491 | int w = 0; 492 | 493 | memset(dbuf, 0, sizeof(dbuf)); 494 | 495 | s = src; 496 | d = dbuf; 497 | if (srclen < 0) 498 | srclen = strlen(src); 499 | 500 | while (1) { 501 | int c; 502 | 503 | c = xdigit2bin(srclen > 0 ? *s : '\0', delim); 504 | if (!(c & state)) 505 | goto out; 506 | if (c & (IN6PTON_DELIM | IN6PTON_COLON_MASK)) { 507 | /* process one 16-bit word */ 508 | if (!(state & IN6PTON_NULL)) { 509 | *d++ = (w >> 8) & 0xff; 510 | *d++ = w & 0xff; 511 | } 512 | w = 0; 513 | if (c & IN6PTON_DELIM) { 514 | /* We've processed last word */ 515 | break; 516 | } 517 | /* 518 | * COLON_1 => XDIGIT 519 | * COLON_2 => XDIGIT|DELIM 520 | * COLON_1_2 => COLON_2 521 | */ 522 | switch (state & IN6PTON_COLON_MASK) { 523 | case IN6PTON_COLON_2: 524 | dc = d; 525 | state = IN6PTON_XDIGIT | IN6PTON_DELIM; 526 | if (dc - dbuf >= sizeof(dbuf)) 527 | state |= IN6PTON_NULL; 528 | break; 529 | case IN6PTON_COLON_1|IN6PTON_COLON_1_2: 530 | state = IN6PTON_XDIGIT | IN6PTON_COLON_2; 531 | break; 532 | case IN6PTON_COLON_1: 533 | state = IN6PTON_XDIGIT; 534 | break; 535 | case IN6PTON_COLON_1_2: 536 | state = IN6PTON_COLON_2; 537 | break; 538 | default: 539 | state = 0; 540 | } 541 | tok = s + 1; 542 | goto cont; 543 | } 544 | 545 | if (c & IN6PTON_DOT) { 546 | ret = in4_pton(tok ? tok : s, srclen + (int)(s - tok), d, delim, &s); 547 | if (ret > 0) { 548 | d += 4; 549 | break; 550 | } 551 | goto out; 552 | } 553 | 554 | w = (w << 4) | (0xff & c); 555 | state = IN6PTON_COLON_1 | IN6PTON_DELIM; 556 | if (!(w & 0xf000)) { 557 | state |= IN6PTON_XDIGIT; 558 | } 559 | if (!dc && d + 2 < dbuf + sizeof(dbuf)) { 560 | state |= IN6PTON_COLON_1_2; 561 | state &= ~IN6PTON_DELIM; 562 | } 563 | if (d + 2 >= dbuf + sizeof(dbuf)) { 564 | state &= ~(IN6PTON_COLON_1|IN6PTON_COLON_1_2); 565 | } 566 | cont: 567 | if ((dc && d + 4 < dbuf + sizeof(dbuf)) || 568 | d + 4 == dbuf + sizeof(dbuf)) { 569 | state |= IN6PTON_DOT; 570 | } 571 | if (d >= dbuf + sizeof(dbuf)) { 572 | state &= ~(IN6PTON_XDIGIT|IN6PTON_COLON_MASK); 573 | } 574 | s++; 575 | srclen--; 576 | } 577 | 578 | i = 15; d--; 579 | 580 | if (dc) { 581 | while(d >= dc) 582 | dst[i--] = *d--; 583 | while(i >= dc - dbuf) 584 | dst[i--] = 0; 585 | while(i >= 0) 586 | dst[i--] = *d--; 587 | } else 588 | memcpy(dst, dbuf, sizeof(dbuf)); 589 | 590 | ret = 1; 591 | out: 592 | if (end) 593 | *end = s; 594 | return ret; 595 | } 596 | #endif /* IN6PTON_XDIGIT */ 597 | 598 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,2,0) 599 | # define sock_create_kern(f, t, p, s) sock_create_kern(&init_net, f, t, p, s) 600 | #endif 601 | 602 | #if !defined(vlan_tx_tag_get) && defined(skb_vlan_tag_get) 603 | # define vlan_tx_tag_get skb_vlan_tag_get 604 | # define vlan_tx_tag_present skb_vlan_tag_present 605 | #endif 606 | 607 | #ifndef SPEED_UNKNOWN 608 | # define SPEED_UNKNOWN -1 609 | #endif 610 | 611 | #if !defined __GNUC_PREREQ && defined __GNUC__ && defined __GNUC_MINOR__ 612 | # define __GNUC_PREREQ(maj, min) \ 613 | ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) 614 | #else 615 | # define __GNUC_PREREQ(maj, min) 0 616 | #endif 617 | 618 | /* ktime is not union anymore, since 2456e855354415bfaeb7badaa14e11b3e02c8466 */ 619 | #if LINUX_VERSION_CODE < KERNEL_VERSION(4,10,0) 620 | # define first_tv64 first.tv64 621 | # define last_tv64 last.tv64 622 | #else 623 | # define first_tv64 first 624 | # define last_tv64 last 625 | #endif 626 | 627 | /* Offset changes made in 613dbd95723aee7abd16860745691b6c7bda20dc */ 628 | #ifndef HAVE_XT_FAMILY 629 | # if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) 630 | # define xt_action_param xt_target_param 631 | # endif 632 | static inline u_int8_t xt_family(const struct xt_action_param *par) 633 | { 634 | return par->family; 635 | } 636 | static inline const struct net_device *xt_in(const struct xt_action_param *par) 637 | { 638 | return par->in; 639 | } 640 | static inline const struct net_device *xt_out(const struct xt_action_param *par) 641 | { 642 | return par->out; 643 | } 644 | static inline unsigned int xt_hooknum(const struct xt_action_param *par) 645 | { 646 | return par->hooknum; 647 | } 648 | #endif 649 | 650 | #ifndef SK_CAN_REUSE 651 | # define SK_CAN_REUSE 1 652 | #endif 653 | 654 | #if LINUX_VERSION_CODE < KERNEL_VERSION(4,13,0) 655 | # define compat_refcount_read atomic_read 656 | #else 657 | # define compat_refcount_read refcount_read 658 | #endif 659 | 660 | #if LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0) 661 | # define timer_setup setup_timer 662 | #endif 663 | 664 | #if LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0) 665 | static int dev_get_alias(const struct net_device *dev, char *name, size_t len) 666 | { 667 | return snprintf(name, len, "%s", dev->ifalias); 668 | } 669 | #else 670 | /* no static because defined in include/linux/netdevice.h, 671 | * but forgot to create EXPORT_SYMBOL, 672 | * probably will collide with some future kernel */ 673 | int dev_get_alias(const struct net_device *dev, char *name, size_t len) 674 | { 675 | const struct dev_ifalias *alias; 676 | int ret = 0; 677 | 678 | rcu_read_lock(); 679 | alias = rcu_dereference(dev->ifalias); 680 | if (alias) 681 | ret = snprintf(name, len, "%s", alias->ifalias); 682 | rcu_read_unlock(); 683 | 684 | return ret; 685 | } 686 | #endif 687 | 688 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,39) && !defined(RHEL_MAJOR) 689 | static inline int is_vlan_dev(struct net_device *dev) 690 | { 691 | return dev->priv_flags & IFF_802_1Q_VLAN; 692 | } 693 | #endif 694 | 695 | #ifdef CONFIG_BRIDGE_NETFILTER 696 | # ifndef HAVE_NF_BRIDGE_INFO_GET 697 | static inline struct nf_bridge_info * 698 | nf_bridge_info_get(const struct sk_buff *skb) 699 | { 700 | return skb->nf_bridge; 701 | } 702 | # endif 703 | #endif 704 | 705 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0) 706 | static inline void do_gettimeofday(struct timeval *tv) 707 | { 708 | struct timespec64 ts64; 709 | ktime_get_real_ts64(&ts64); 710 | tv->tv_sec = ts64.tv_sec; 711 | tv->tv_usec = ts64.tv_nsec/1000; 712 | } 713 | #endif 714 | 715 | #define TOLOWER(x) ((x) | 0x20) 716 | unsigned long long strtoul(const char *cp, char **endp, unsigned int base) 717 | { 718 | unsigned long long result = 0; 719 | 720 | if (!base) { 721 | if (cp[0] == '0') { 722 | if (TOLOWER(cp[1]) == 'x' && isxdigit(cp[2])) 723 | base = 16; 724 | else 725 | base = 8; 726 | } else { 727 | base = 10; 728 | } 729 | } 730 | 731 | if (base == 16 && cp[0] == '0' && TOLOWER(cp[1]) == 'x') 732 | cp += 2; 733 | 734 | while (isxdigit(*cp)) { 735 | unsigned int value; 736 | 737 | value = isdigit(*cp) ? *cp - '0' : TOLOWER(*cp) - 'a' + 10; 738 | if (value >= base) 739 | break; 740 | result = result * base + value; 741 | cp++; 742 | } 743 | if (endp) 744 | *endp = (char *)cp; 745 | 746 | return result; 747 | } 748 | 749 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(5,12,0) 750 | /* 751 | * find_module() is unexported in v5.12: 752 | * 089049f6c9956 ("module: unexport find_module and module_mutex") 753 | * and module_mutex is replaced with RCU in 754 | * a006050575745 ("module: use RCU to synchronize find_module") 755 | */ 756 | #include 757 | struct module *find_module(const char *name) 758 | { 759 | struct module *mod; 760 | 761 | rcu_read_lock_sched(); 762 | /* Yes this is crazy, but should work. */ 763 | list_for_each_entry_rcu(mod, &THIS_MODULE->list, list) { 764 | if (!strcmp(mod->name, name)) { 765 | rcu_read_unlock_sched(); 766 | return mod; 767 | } 768 | } 769 | rcu_read_unlock_sched(); 770 | return NULL; 771 | } 772 | #endif 773 | 774 | /* Copy from 294f69e662d1 ("compiler_attributes.h: Add 'fallthrough' pseudo 775 | * keyword for switch/case use") */ 776 | #ifndef fallthrough 777 | # if defined __has_attribute && __has_attribute(__fallthrough__) 778 | # define fallthrough __attribute__((__fallthrough__)) 779 | # else 780 | # define fallthrough do {} while (0) /* fallthrough */ 781 | # endif 782 | #endif 783 | 784 | #ifndef HAVE_NF_CT_EVENT_NOTIFIER_CT_EVENT 785 | /* 786 | * nat event callback parameter is constified in 5.15+ 787 | * but it prevents module building with previous kernel versions 788 | */ 789 | # define NF_CT_EVENT struct nf_ct_event 790 | # define ct_event fcn 791 | #else 792 | # define NF_CT_EVENT const struct nf_ct_event 793 | #endif 794 | 795 | #if LINUX_VERSION_CODE < KERNEL_VERSION(4,4,0) 796 | static inline bool netif_is_bridge_port(const struct net_device *dev) 797 | { 798 | return dev->priv_flags & IFF_BRIDGE_PORT; 799 | } 800 | #endif 801 | 802 | #endif /* COMPAT_NETFLOW_H */ 803 | -------------------------------------------------------------------------------- /configure: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # SPDX-License-Identifier: GPL-2.0-only 3 | 4 | PATH=$PATH:/bin:/usr/bin:/usr/sbin:/sbin:/usr/local/sbin 5 | 6 | case "$1" in 7 | --from-dkms-conf*) 8 | KDKMS=`echo "$1" | sed 's/[^=]*.//'` 9 | # restore options from existing Makefile, if present 10 | if [ -e Makefile ]; then 11 | set -- `sed -n 's/^CARGS = \(.*\)/\1/p' Makefile` 12 | FROMDKMSCONF=1 13 | fi 14 | ;; 15 | esac 16 | 17 | error() { 18 | printf "! Error: $*\n" 19 | exit 1 20 | } 21 | 22 | iptables_src_version() { 23 | test "$IPTSRC" || return 1 24 | 25 | echo -n "Checking iptables sources version: " 26 | SRC="$IPTSRC/Makefile" 27 | test -s "$SRC" || error "Please build iptables first." 28 | VER=`sed -n 's/^\(IPTABLES_\)\?VERSION[ :]= \?//p' "$SRC"` 29 | test "$VER" || error "Unknown version of iptables." 30 | if [ "$VER" = "$IPTVER" ]; then 31 | echo "$VER (ok)" 32 | else 33 | echo "$VER" 34 | error "Source version ($VER) doesn't match binary ($IPTVER)" 35 | fi 36 | } 37 | 38 | get_lib_dir() { 39 | test -s "$1" && LIB=`sed -n 's/.*_LIB_DIR "\(.*\)"/\1/p' "$1"` 40 | if [ "$LIB" ]; then 41 | IPTLIB=$LIB 42 | echo "$IPTLIB (from sources)" 43 | return 0 44 | fi 45 | return 1 46 | } 47 | 48 | get_lib_from_bin() { 49 | LIB=`strings $IPTBIN | grep ^/.*lib.*/.*tables` 50 | if [ "$LIB" ]; then 51 | IPTLIB=$LIB 52 | echo "$IPTLIB (from binary)" 53 | return 0 54 | fi 55 | return 1 56 | } 57 | 58 | get_lib_from_lib() { 59 | XLIB=`/usr/bin/ldd $IPTBIN | grep libxtables | sed -n 's!.* \(/[^ ]\+\).*!\1!p'` 60 | test "$XLIB" || return 1 61 | LIB=`strings $XLIB | grep ^/.*lib.*/.*tables` 62 | if [ "$LIB" ]; then 63 | IPTLIB=$LIB 64 | echo "$IPTLIB (from libxtables.so, from binary)" 65 | return 0 66 | fi 67 | return 1 68 | } 69 | 70 | iptables_inc() { 71 | echo -n "Iptables include flags: " 72 | if [ "$IPTINC" ]; then 73 | echo "$IPTINC (user specified)" 74 | elif [ "$PKGVER" ]; then 75 | IPTINC="$PKGINC" 76 | echo "$IPTINC (pkg-config)" 77 | elif [ "$NOIPTSRC" ]; then 78 | IPTINC= 79 | echo "none (default)" 80 | else 81 | IPTINC="$IPTSRC/include" 82 | IPTINC="-I$IPTINC" 83 | echo "$IPTINC (from source)" 84 | fi 85 | } 86 | 87 | iptables_modules() { 88 | echo -n "Iptables module path: " 89 | if [ "$IPTLIB" ]; then 90 | echo "$IPTLIB (user specified)" 91 | else 92 | if [ "$PKGLIB" ]; then 93 | IPTLIB="$PKGLIB" 94 | echo "$IPTLIB (pkg-config)" 95 | else 96 | get_lib_dir "$IPTSRC/include/iptables.h" && return 0 97 | get_lib_dir "$IPTSRC/include/xtables.h" && return 0 98 | get_lib_dir "$IPTSRC/xtables/internal.h" && return 0 99 | get_lib_from_bin && return 0 100 | get_lib_from_lib && return 0 101 | error "can not find, try setting it with --ipt-lib=" 102 | fi 103 | fi 104 | } 105 | 106 | try_dir() { 107 | if [ -d "$1/include" ]; then 108 | echo "Found iptables sources at $1" 109 | IPTSRC=$1 110 | return 0 111 | fi 112 | return 1 113 | } 114 | 115 | try_dirg() { 116 | try_dir "$1" && return 0 117 | try_dir "$1.git" && return 0 118 | } 119 | 120 | try_dir2() { 121 | test -d "$1" && try_dir `dirname $1` && return 0 122 | } 123 | 124 | check_pkg_config() { 125 | test "$PKGWARN" && return 1 126 | if ! which pkg-config >/dev/null 2>&1; then 127 | echo "! You don't have pkg-config, it may be useful to install it." 128 | PKGWARN=1 129 | return 1 130 | fi 131 | return 0 132 | } 133 | iptables_find_version() { 134 | echo -n "Iptables binary version: " 135 | if [ "$IPTVER" ]; then 136 | echo "$IPTVER (user specified)" 137 | else 138 | IPTVER=`$IPTBIN -V 2>/dev/null | sed -n s/iptables.v//p` 139 | if [ "$IPTVER" ]; then 140 | echo "$IPTVER (detected from $IPTBIN)" 141 | return 142 | else 143 | echo "no iptables binary found" 144 | fi 145 | check_pkg_config 146 | PKGVER=`pkg-config --modversion xtables 2>/dev/null` 147 | if [ "$PKGVER" ]; then 148 | IPTVER="$PKGVER" 149 | echo "Xtables version: $IPTVER (detected from `which pkg-config`)" 150 | return 151 | fi 152 | error "Can not find iptables version, try setting it with --ipt-ver=" 153 | fi 154 | } 155 | 156 | compiler_presence_test() { 157 | echo -n "Check for working gcc: " 158 | $CC -v >/dev/null 2>&1 159 | if [ $? = 0 ]; then 160 | echo Yes "($CC)" 161 | else 162 | echo No 163 | 164 | echo "! You need gcc to install module from source" 165 | if [ -s /etc/debian_version ]; then 166 | NAME=Debian 167 | if [ -e /etc/os-release ]; then 168 | . /etc/os-release >/dev/null 2>&1 169 | fi 170 | echo "! " 171 | echo "! Under $NAME try to run this:" 172 | echo "! root# apt-get install gcc" 173 | echo "! " 174 | elif [ -s /etc/redhat-release ]; then 175 | echo "! " 176 | echo "! Under Centos try to run this:" 177 | echo "! root# yum install gcc" 178 | echo "! " 179 | fi 180 | exit 1 181 | fi 182 | } 183 | 184 | compile_libitp_test() { 185 | local FLAGS 186 | local MSG 187 | echo -n "Checking for presence of $@... " 188 | if [ "$IPTINC" ]; then 189 | FLAGS=$IPTINC 190 | MSG="(using ipt-inc)" 191 | elif [ "$PKGINC" ]; then 192 | FLAGS=$PKGINC 193 | MSG="(using pkg-config)" 194 | else 195 | FLAGS= 196 | MSG= 197 | fi 198 | echo " 199 | #define __EXPORTED_HEADERS__ 200 | #include <$*>" > test.c 201 | $CC -c test.c $FLAGS >/dev/null 2>&1 202 | RET=$? 203 | if [ $RET = 0 ]; then 204 | echo Yes $MSG; 205 | else 206 | echo No; 207 | fi 208 | rm -f test.c test.o 209 | return $RET 210 | } 211 | 212 | iptables_try_pkgconfig() { 213 | if [ ! "$PKGVER" ]; then 214 | check_pkg_config 215 | PKGVER=`pkg-config --modversion xtables 2>/dev/null` 216 | TRYPKGVER=`pkg-config --modversion xtables 2>/dev/null` 217 | echo -n "pkg-config for version $IPTVER exists: " 218 | pkg-config --exact-version=$IPTVER xtables 2>/dev/null 219 | if [ $? = 0 ]; then 220 | echo "Yes" 221 | PKGVER=$TRYPKGVER 222 | else 223 | if [ "$TRYPKGVER" ]; then 224 | echo "No (reported: $TRYPKGVER)" 225 | else 226 | echo "No" 227 | fi 228 | PKGVER= 229 | fi 230 | fi 231 | if [ "$PKGVER" ]; then 232 | check_pkg_config 233 | PKGVER=`pkg-config --modversion xtables 2>/dev/null` 234 | PKGINC=`pkg-config --cflags xtables` 235 | PKGLIB=`pkg-config --variable=xtlibdir xtables` 236 | elif expr "$IPTVER" : '^1\.3' >/dev/null; then 237 | echo "! This version of iptables ($IPTVER) will be treated as old version." 238 | # Newer versions of iptables should not have -I/kernel/include! 239 | # So I assume that newer version will have correct pkg-config set up 240 | # and if not, then it's older who need it. 241 | IPTCFLAGS="-I$KDIR/include -DIPTABLES_VERSION=\\\\\"$IPTVER\\\\\"" 242 | fi 243 | compiler_presence_test 244 | if compile_libitp_test xtables.h; then 245 | IPTCFLAGS="-DXTABLES $IPTCFLAGS" 246 | elif ! compile_libitp_test iptables.h; then 247 | echo "! Iptables headers not found. You may need to specify --ipt-inc=..." 248 | if [ -s /etc/debian_version ]; then 249 | echo "! " 250 | echo "! Under Debian simply run this:" 251 | if apt-cache policy libxtables-dev 2>&1 | grep -F -q "Candidate:"; then 252 | echo "! root# apt-get install libxtables-dev pkg-config" 253 | else 254 | echo "! root# apt-get install iptables-dev pkg-config" 255 | fi 256 | elif [ -s /etc/redhat-release ]; then 257 | echo "! " 258 | arch=.`uname -m` 259 | echo "! Under Centos simply run this:" 260 | echo "! root# yum install iptables-devel$arch pkgconfig" 261 | fi 262 | exit 1 263 | fi 264 | 265 | } 266 | 267 | iptables_find_src() { 268 | test "$IPTINC" && return 1 269 | test "$PKGVER" && return 1 270 | 271 | VER="iptables-$IPTVER" 272 | if [ "$IPTSRC" ]; then 273 | echo "User specified source directory: $IPTSRC" 274 | try_dir $IPTSRC || error "Specified directory is not iptables source.." 275 | else 276 | echo "Searching for $VER sources.." 277 | try_dir "./$VER" && return 0 278 | try_dir "../$VER" && return 0 279 | try_dir "/usr/src/$VER" && return 0 280 | try_dirg "iptables" && return 0 281 | try_dirg "../iptables" && return 0 282 | try_dirg "/usr/src/iptables" && return 0 283 | try_dir2 `locate $VER/extensions 2>/dev/null | head -1` && return 0 284 | echo "! Can not find iptables source directory, you may try setting it with --ipt-src=" 285 | echo "! This is not fatal error, yet. Will be just using default include dir." 286 | NOIPTSRC=1 287 | fi 288 | } 289 | 290 | show_help() { 291 | echo "Possible options:" 292 | echo " --ipt-ver=.. iptables version (ex.: 1.4.2)" 293 | echo " --ipt-bin=.. iptables binary to use (ex.: /usr/sbin/iptables)" 294 | echo " --ipt-src=.. directory for iptable source (ex.: ../iptables-1.4.2)" 295 | echo " --ipt-lib=.. iptable modules path (ex.: /usr/libexec/xtables)" 296 | echo " --ipt-inc=.. directory for iptable headers (ex.: /usr/include)" 297 | echo " --kver=.. kernel version (ex.: 2.6.30-std-def-alt15)" 298 | echo " --kdir=.. directory for kernel source (ex.: /usr/src/kernel)" 299 | echo " --enable-natevents enables natevents support" 300 | echo " --enable-snmp-rules enables SNMP-index conversion rules" 301 | echo " --enable-macaddress enables MAC address for v9/IPFIX" 302 | echo " --enable-vlan enables VLAN Ids for v9/IPFIX" 303 | echo " --enable-direction enables flowDirection(61) Element" 304 | echo " --enable-sampler enables Flow Sampling" 305 | echo " --enable-sampler=hash enables Hash sampler" 306 | echo " --enable-rand-tpl-id enables seeding the template IDs from a random number" 307 | echo " --enable-aggregation enables aggregation rules" 308 | echo " --enable-promisc enables promisc hack mode" 309 | echo " --promisc-mpls decapsulate MPLS in promisc mode" 310 | echo " --promisc-mpls=N -- and record N labels (default 3)" 311 | echo " --enable-physdev enables physdev reporting" 312 | echo " --enable-physdev-override to override interfaces" 313 | echo " --disable-snmp-agent disables net-snmp agent" 314 | echo " --disable-dkms disables DKMS support completely" 315 | echo " --disable-dkms-install no DKMS install but still create dkms.conf" 316 | exit 0 317 | } 318 | 319 | CARGS="$@" 320 | for ac_option 321 | do 322 | case "$ac_option" in 323 | -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; 324 | *) ac_optarg= ;; 325 | esac 326 | 327 | case "$ac_option" in 328 | --ipt-bin=*) IPTBIN="$ac_optarg" ;; 329 | --ipt-lib=*) IPTLIB="$ac_optarg" ;; 330 | --ipt-src=*) IPTSRC="$ac_optarg" ;; 331 | --ipt-ver=*) IPTVER="$ac_optarg" ;; 332 | --ipt-inc=*) IPTINC="-I$ac_optarg" ;; 333 | --kver=*) KVERSION="$ac_optarg" ;; 334 | --kdir=*) KDIR="$ac_optarg" ;; 335 | --enable-nat*) KOPTS="$KOPTS -DENABLE_NAT" ;; 336 | --enable-mac*) KOPTS="$KOPTS -DENABLE_MAC" ;; 337 | --enable-vlan*) KOPTS="$KOPTS -DENABLE_VLAN" ;; 338 | --enable-direc*) KOPTS="$KOPTS -DENABLE_DIRECTION" ;; 339 | --enable-sampl*hash) KOPTS="$KOPTS -DENABLE_SAMPLER -DSAMPLING_HASH" ;; 340 | --enable-sampl*) KOPTS="$KOPTS -DENABLE_SAMPLER" ;; 341 | --enable-aggr*) KOPTS="$KOPTS -DENABLE_AGGR" ;; 342 | --enable-rand-tpl*) KOPTS="$KOPTS -DENABLE_RANDOM_TEMPLATE_IDS" ;; 343 | --enable-promi*) ENABLE_PROMISC=1 ;; 344 | --promisc-mpls*) ENABLE_PROMISC=1; PROMISC_MPLS=1; MPLS_DEPTH=${ac_optarg:-3} ;; 345 | --enable-snmp-r*) KOPTS="$KOPTS -DSNMP_RULES" ;; 346 | --enable-physdev) KOPTS="$KOPTS -DENABLE_PHYSDEV" ;; 347 | --enable-physdev-over*) KOPTS="$KOPTS -DENABLE_PHYSDEV_OVER" ;; 348 | --disable-snmp-a*) SKIPSNMP=1 ;; 349 | --disable-net-snmp*) SKIPSNMP=1 ;; 350 | --disable-dkms*) SKIPDKMS=1 ;; 351 | --from-dkms-conf*) ;; 352 | --make) echo called from make; CARGS=`echo $CARGS | sed s/--make//g` ;; 353 | -Werror) KOPTS="$KOPTS -Werror" ;; 354 | --help|-h) show_help ;; 355 | -*) echo Invalid option: $ac_option; exit 1 ;; 356 | # *) ni="$ni $ac_option" ;; 357 | esac 358 | done 359 | 360 | if [ "$ENABLE_PROMISC" = 1 ]; then KOPTS="$KOPTS -DENABLE_PROMISC"; fi 361 | if [ "$PROMISC_MPLS" = 1 ]; then 362 | KOPTS="$KOPTS -DPROMISC_MPLS" 363 | case "$MPLS_DEPTH" in (*[!0-9]*|"") MPLS_DEPTH=1 ;; esac 364 | if [ "$MPLS_DEPTH" -lt 1 ]; then 365 | echo "! Requested MPLS stack depth is too small, limiting to 1." 366 | elif [ "$MPLS_DEPTH" -gt 10 ]; then 367 | echo "! Requested MPLS stack depth is too big, limiting to 10." 368 | MPLS_DEPTH=10; 369 | fi 370 | if [ "$MPLS_DEPTH" -ge 1 ]; then KOPTS="$KOPTS -DMPLS_DEPTH=$MPLS_DEPTH"; fi 371 | fi 372 | 373 | kernel_find_version() { 374 | KHOW=requested 375 | test "$KVERSION" && return 0 376 | 377 | if grep -q '#.*Debian' /proc/version; then 378 | KHOW=proc 379 | KVERSION=`sed -n 's/.*#.*Debian \([0-9\.]\+\)-.*/\1/p' /proc/version` 380 | KLIBMOD=`uname -r` 381 | else 382 | KHOW=uname 383 | KVERSION=`uname -r` 384 | fi 385 | test "$KDIR" || return 0 386 | 387 | test -s $KDIR/Makefile || return 1 388 | test -s $KDIR/include/config/kernel.release || return 1 389 | KVERSION=`cat $KDIR/include/config/kernel.release` 390 | KHOW=sources 391 | } 392 | 393 | kernel_check_src() { 394 | if [ -s "$1/Makefile" ]; then 395 | KDIR="$1" 396 | return 0 397 | fi 398 | return 1 399 | } 400 | 401 | kernel_check_src2() { 402 | if kernel_check_src $1/source; then 403 | KSRC=$KDIR 404 | fi 405 | kernel_check_src $1/build 406 | } 407 | 408 | kernel_find_source() { 409 | if [ "$KDKMS" ]; then 410 | # dkms args is highest priority 411 | KDIR=$KDKMS 412 | KSHOW=dkms 413 | return 0 414 | fi 415 | KSHOW=requested 416 | test "$KDIR" && return 0 417 | KSHOW=found 418 | kernel_check_src2 /lib/modules/$KLIBMOD && return 0 419 | kernel_check_src2 /lib/modules/$KVERSION && return 0 420 | kernel_check_src /usr/src/kernels/$KVERSION && return 0 421 | kernel_check_src /usr/src/linux-$KVERSION && return 0 422 | echo "! Linux source not found. Don't panic. You may specify kernel source" 423 | echo "! directory with --kdir=..., or try to install kernel-devel package," 424 | echo "! or just raw sources for linux-$KVERSION from kernel.org." 425 | if grep -q -i centos /proc/version 2>/dev/null; then 426 | echo "! " 427 | arch=.`uname -m` 428 | echo "! Under Centos simply run this:" 429 | echo "! root# yum install kernel-devel iptables-devel$arch pkgconfig" 430 | fi 431 | if grep -q -i debian /proc/version 2>/dev/null; then 432 | echo "! " 433 | echo "! Under Debian simply run this:" 434 | echo "! root# apt-get install module-assistant iptables-dev pkg-config" 435 | echo "! root# m-a prepare" 436 | fi 437 | exit 1 438 | } 439 | 440 | kernel_check_consistency() { 441 | if [ -s $KDIR/include/config/kernel.release ]; then 442 | SRCVER=`cat $KDIR/include/config/kernel.release` 443 | if [ "$KVERSION" != "$SRCVER" ]; then 444 | echo "! Warning: $KHOW kernel version ($KVERSION) and $KSHOW version of kernel source ($SRCVER) doesn't match!" 445 | echo "! You may try to specify only kernel source tree with --kdir=$KDIR" 446 | echo "! and configure will pick up version properly." 447 | echo "! Assuming you want to build for $SRCVER" 448 | KVERSION=$SRCVER 449 | fi 450 | fi 451 | test -e "$KDIR/.config" || error ".config in kernel source not found, run make menuconfig in $KDIR" 452 | test -d "$KDIR/include/config" || error "kernel is not prepared, run make prepare modules_prepare in $KDIR" 453 | } 454 | 455 | kconfig() { 456 | KCONFIG=$KDIR/.config 457 | if ! grep -q "^$1=" $KCONFIG 2>/dev/null; then 458 | if [ "$KCONFIGREPORTED" != true ]; then 459 | KCONFIGREPORTED=true 460 | echo Kernel config file checked: $KCONFIG 461 | echo 462 | fi 463 | echo "! Attention: $1 is undefined in your kernel configuration" 464 | echo "! Without this option enabled $2 will not work." 465 | echo 466 | return 1 467 | fi 468 | return 0 469 | } 470 | 471 | # Respond to change in https://github.com/torvalds/linux/commit/4806e975729f99 472 | nf_nat_needed() { 473 | local INC=include/linux/netfilter.h 474 | 475 | echo -n "Checking for presence of $INC... " 476 | if [ "$KSRC" -a -e $KSRC/$INC ]; then 477 | echo Yes 478 | INC=$KSRC/$INC 479 | elif [ -e $KDIR/$INC ]; then 480 | echo Yes 481 | INC=$KDIR/$INC 482 | else 483 | echo No 484 | return 1 485 | fi 486 | echo -n "netfilter.h uses CONFIG_NF_NAT_NEEDED... " 487 | if grep -q CONFIG_NF_NAT_NEEDED $INC; then 488 | echo Yes 489 | else 490 | echo No 491 | return 1 492 | fi 493 | } 494 | 495 | kernel_check_config() { 496 | kconfig CONFIG_SYSCTL "sysctl interface" 497 | kconfig CONFIG_PROC_FS "proc interface" 498 | if nf_nat_needed; then 499 | kconfig CONFIG_NF_NAT_NEEDED "natevents" 500 | else 501 | kconfig CONFIG_NF_NAT "natevents" && KOPTS="$KOPTS -DCONFIG_NF_NAT_NEEDED" 502 | fi 503 | kconfig CONFIG_NF_CONNTRACK_EVENTS "natevents" 504 | kconfig CONFIG_IPV6 "IPv6" 505 | kconfig CONFIG_IP6_NF_IPTABLES "ip6tables target" 506 | kconfig CONFIG_BRIDGE_NETFILTER "physdev override" 507 | } 508 | 509 | kernel_check_include() { 510 | echo -n "Checking for presence of $1... " 511 | if [ "$KSRC" -a -e $KSRC/$1 ]; then 512 | echo Yes 513 | KOPTS="$KOPTS $2" 514 | elif [ -e $KDIR/$1 ]; then 515 | echo Yes 516 | KOPTS="$KOPTS $2" 517 | else 518 | echo No 519 | fi 520 | } 521 | 522 | kernel_check_features() { 523 | kernel_check_include include/linux/llist.h -DHAVE_LLIST 524 | kernel_check_include include/linux/grsecurity.h -DHAVE_GRSECURITY_H 525 | } 526 | 527 | snmp_check() { 528 | SNMPTARGET= 529 | SNMPINSTALL= 530 | test "$SKIPSNMP" && return 531 | 532 | echo -n "Searching for net-snmp-config... " 533 | if which net-snmp-config >/dev/null 2>&1; then 534 | echo Yes `which net-snmp-config` 535 | else 536 | echo No. 537 | SNMPCONFIG=no 538 | fi 539 | 540 | echo -n "Searching for net-snmp agent... " 541 | if [ -s /etc/redhat-release ]; then 542 | if ! rpm --quiet -q net-snmp; then 543 | echo No. 544 | SNMPADD="do: yum install net-snmp" 545 | if [ "$SNMPCONFIG" ]; then 546 | SNMPADD="$SNMPADD net-snmp-devel" 547 | fi 548 | else 549 | echo Yes. 550 | fi 551 | if [ "$SNMPCONFIG" ]; then 552 | SNMPCONFIG="run: yum install net-snmp-devel" 553 | fi 554 | elif [ -s /etc/debian_version ]; then 555 | if ! dpkg -s snmpd >/dev/null 2>&1; then 556 | echo No. 557 | SNMPADD="do: apt-get install snmpd" 558 | if [ "$SNMPCONFIG" ]; then 559 | SNMPADD="$SNMPADD libsnmp-dev" 560 | fi 561 | else 562 | echo Yes. 563 | fi 564 | if [ "$SNMPCONFIG" ]; then 565 | SNMPCONFIG="run: apt-get install libsnmp-dev" 566 | fi 567 | elif [ -s /etc/snmp/snmpd.conf ]; then 568 | echo Yes. 569 | else 570 | echo No. 571 | SNMPADD="install net-snmp (www.net-snmp.org)" 572 | SNMPCONFIG="reinstall net-snmp with agent support." 573 | fi 574 | 575 | if [ "$SNMPADD" ]; then 576 | echo " Assuming you don't want net-snmp agent support". 577 | echo " Otherwise $SNMPADD" 578 | return 579 | elif [ "$SNMPCONFIG" ]; then 580 | echo "! You have net-snmp agent but not development package." 581 | echo "! net-snmp agent will not be built, to fix:" 582 | echo "! $SNMPCONFIG" 583 | return 584 | fi 585 | 586 | SNMPTARGET=snmp_NETFLOW.so 587 | SNMPINSTALL=sinstall 588 | } 589 | 590 | dkms_check() { 591 | DKMSINSTALL= 592 | test "$SKIPDKMS" && return 593 | 594 | echo -n "Checking for DKMS... " 595 | if ! which dkms >/dev/null 2>&1; then 596 | echo "No. (It may be useful to install it.)" 597 | echo "! " 598 | echo "! DKMS is method of installing kernel modules, that will" 599 | echo "! automatically recompile module after kernel upgrade." 600 | if [ -s /etc/debian_version ]; then 601 | echo "! " 602 | echo "! To install it under Debian simply run this:" 603 | echo "! root# apt-get install dkms" 604 | echo "! " 605 | elif [ -s /etc/redhat-release ]; then 606 | echo "! " 607 | echo "! To install it under Centos enable EPEL or RPMforge repository," 608 | echo "! then run this:" 609 | echo "! root# yum install dkms" 610 | echo "! " 611 | fi 612 | return 613 | fi 614 | echo Yes. 615 | DKMSINSTALL=dinstall 616 | test "$FROMDKMSCONF" && return 617 | if dkms status | grep ^ipt-netflow, >/dev/null; then 618 | echo "! You are already have module installed via DKMS" 619 | echo "! it will be uninstalled on 'make install' and" 620 | echo "! current version of module installed afterwards." 621 | echo "! Use --disable-dkms option if don't want this." 622 | fi 623 | } 624 | 625 | echo "Module version: $(./version.sh)" 626 | 627 | kernel_find_version #KVERSION 628 | test "$KLIBMOD" || KLIBMOD=$KVERSION 629 | echo "Kernel version: $KVERSION ($KHOW)" 630 | kernel_find_source #KDIR 631 | echo "Kernel sources: $KDIR ($KSHOW)" 632 | kernel_check_consistency 633 | kernel_check_config 634 | kernel_check_features 635 | 636 | CC=${CC:-gcc} 637 | test "$IPTBIN" || IPTBIN=`which iptables` 638 | 639 | iptables_find_version #IPTVER 640 | iptables_try_pkgconfig #try to configure from pkg-config 641 | iptables_find_src #IPTSRC 642 | iptables_src_version #check that IPTSRC match to IPTVER 643 | iptables_inc #IPTINC 644 | iptables_modules #IPTLIB 645 | 646 | snmp_check 647 | dkms_check 648 | 649 | rm -f compat_def.h 650 | 651 | REPLACE="\ 652 | s!@CARGS@!$CARGS!;\ 653 | s!@KVERSION@!$KVERSION!;\ 654 | s!@KDIR@!$KDIR!;\ 655 | s!@KOPTS@!$KOPTS!;\ 656 | s!@SNMPTARGET@!$SNMPTARGET!;\ 657 | s!@SNMPINSTALL@!$SNMPINSTALL!;\ 658 | s!@DKMSINSTALL@!$DKMSINSTALL!;\ 659 | s!@IPTABLES_VERSION@!$IPTVER!;\ 660 | s!@IPTABLES_CFLAGS@!$IPTCFLAGS $IPTINC!;\ 661 | s!@IPTABLES_MODULES@!$IPTLIB!" 662 | 663 | echo -n "Creating Makefile.. " 664 | sed "$REPLACE" Makefile.in > Makefile 665 | echo done. 666 | echo 667 | echo " If you need some options enabled run ./configure --help" 668 | echo " Now run: make all install" 669 | echo 670 | 671 | -------------------------------------------------------------------------------- /dkms.conf: -------------------------------------------------------------------------------- 1 | PACKAGE_NAME="ipt-netflow" 2 | pushd `dirname $BASH_SOURCE` 3 | PACKAGE_VERSION=`./version.sh` 4 | popd 5 | BUILT_MODULE_NAME[0]=ipt_NETFLOW 6 | DEST_MODULE_LOCATION[0]=/kernel/extra 7 | STRIP[0]=no 8 | MAKE[0]="make ipt_NETFLOW.ko" 9 | PRE_BUILD="./configure --from-dkms-conf=$kernel_source_dir" 10 | AUTOINSTALL=yes 11 | -------------------------------------------------------------------------------- /gen_compat_def: -------------------------------------------------------------------------------- 1 | #!/bin/bash -efu 2 | # SPDX-License-Identifier: GPL-2.0-only 3 | # 4 | # Generate defines based on kernel having some symbols declared. 5 | # Tests should work without linking, because kernel may not be 6 | # completely compiled (only prepared). 7 | # 8 | # Copyright (C) 2019-2021 9 | # 10 | 11 | export LANG=C LC_ALL=C LC_MESSAGES=C LC_CTYPE=C 12 | fatal() { 13 | echo "Error: $*" >&2 14 | exit 1 15 | } 16 | 17 | eval $(grep ^KDIR Makefile | tr -d ' ') 18 | [ "$KDIR" ] || fatal "KDIR is not found" 19 | 20 | WD=cc-test-build 21 | mkdir -p $WD 22 | cd ./$WD || fatal "cannot cd to $WD" 23 | 24 | # args: HAVE_SUMBOL symbol include 25 | kbuild_test_compile() { 26 | local cmd 27 | 28 | cat > test.c 29 | echo obj-m = test.o > Makefile 30 | cmd="make -s -B -C $KDIR M=$PWD modules" 31 | echo "$cmd" > log 32 | if $cmd >> log 2>&1; then 33 | echo " declared" >&2 34 | [ "$2" ] && echo "// $2 is declared ${3:+in <$3>}" 35 | echo "#define HAVE_$1" 36 | echo 37 | else 38 | echo " undeclared" >&2 39 | echo "#undef HAVE_$1" 40 | echo "// ${2:-symbol} is undeclared${3:+ in <$3>}. Compile:" 41 | sed "s/^/\/\/ /" test.c 42 | echo "// Output:" 43 | sed "s/^/\/\/ /" log 44 | echo 45 | if ! grep -E -q \ 46 | -e 'has no member named' \ 47 | -e 'undeclared' \ 48 | -e 'storage size of .* isn.t known' \ 49 | -e 'No such file or directory' \ 50 | -e 'incompatible types when initializing' \ 51 | -e 'initializer element is not constant' \ 52 | -e 'dereferencing pointer to incomplete type' \ 53 | log; then 54 | echo "Error: unexpected error from compiler" >&2 55 | cat log >&2 56 | echo >&2 57 | exit 3 58 | fi 59 | fi 60 | } 61 | 62 | # Test that symbol is defined (will catch functions mostly). 63 | kbuild_test_symbol() { 64 | echo -n "Test function $* " >&2 65 | kbuild_test_compile ${1^^} $1 ${2-} <<-EOF 66 | #include 67 | ${2:+#include <$2>} 68 | MODULE_LICENSE("GPL"); 69 | void *test = $1; 70 | EOF 71 | } 72 | 73 | # Test that symbol is defined (functions and globals). 74 | kbuild_test_ref() { 75 | echo -n "Test symbol $* " >&2 76 | kbuild_test_compile ${1^^}_REF $1 ${2-} <<-EOF 77 | #include 78 | ${2:+#include <$2>} 79 | MODULE_LICENSE("GPL"); 80 | void *test = &$1; 81 | EOF 82 | } 83 | # Test that struct is defined. 84 | kbuild_test_struct() { 85 | echo -n "Test struct $* " >&2 86 | kbuild_test_compile ${1^^} "struct $1" ${2-} <<-EOF 87 | #include 88 | ${2:+#include <$2>} 89 | MODULE_LICENSE("GPL"); 90 | struct $1 test; 91 | EOF 92 | } 93 | 94 | # Test that struct have member 95 | kbuild_test_member() { 96 | echo -n "Test member $* " >&2 97 | structname=${1%.*} 98 | member=${1#*.} 99 | def=${1^^} 100 | def=${def//./_} 101 | kbuild_test_compile $def "struct $1" ${2-} <<-EOF 102 | #include 103 | ${2:+#include <$2>} 104 | MODULE_LICENSE("GPL"); 105 | typeof(((struct $structname*)0)->$member) test; 106 | EOF 107 | } 108 | echo "// Autogenerated for $KDIR" 109 | echo 110 | 111 | # helpers introduced in 613dbd95723aee7abd16860745691b6c7bda20dc 112 | kbuild_test_symbol xt_family linux/netfilter_ipv4/ip_tables.h 113 | kbuild_test_struct timeval linux/ktime.h 114 | # 97a32539b9568 proc: convert everything to "struct proc_ops" 115 | # d56c0d45f0e27 proc: decouple proc from VFS with "struct proc_ops" 116 | kbuild_test_struct proc_ops linux/proc_fs.h 117 | # No since v5.1, but present in CentOS-8's 4.18.0-227 118 | kbuild_test_symbol synchronize_sched linux/rcupdate.h 119 | # Fails on 3.10.0-957.10.1.el7.x86_64 120 | kbuild_test_symbol nf_bridge_info_get linux/netfilter_bridge.h 121 | # Stumbled on 5.9 122 | kbuild_test_struct vlan_dev_priv linux/if_vlan.h 123 | # Kernel version check broken by centos8 124 | kbuild_test_symbol put_unaligned_be24 asm/unaligned.h 125 | # totalram_pages changed from atomic to inline function. 126 | kbuild_test_symbol totalram_pages linux/mm.h 127 | kbuild_test_ref totalram_pages linux/mm.h 128 | # b86c0e6429da ("netfilter: ecache: prepare for event notifier merge") 129 | kbuild_test_member nf_ct_event_notifier.ct_event net/netfilter/nf_conntrack_ecache.h 130 | # 6.4: 0199849acd07 ("sysctl: remove register_sysctl_paths()") 131 | kbuild_test_symbol register_sysctl_paths linux/sysctl.h 132 | 133 | echo "// End of compat_def.h" 134 | 135 | cd $OLDPWD 136 | rm -rf $WD 137 | 138 | # debug output for Travis 139 | if [ -z "${PWD/*travis*}" ]; then 140 | cat compat_def.h >&2 141 | fi 142 | -------------------------------------------------------------------------------- /install-dkms.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # SPDX-License-Identifier: GPL-2.0-only 3 | # 4 | # This script cleanly re-install module into DKMS tree. 5 | 6 | PATH=$PATH:/bin:/usr/bin:/usr/sbin:/sbin:/usr/local/sbin 7 | 8 | if [ "$1" = --uninstall ]; then 9 | echo "Uninstalling from DKMS..." 10 | elif [ "$1" = --install ]; then 11 | echo "Installing into DKMS..." 12 | else 13 | exit 1 14 | fi 15 | 16 | if ! which dkms >/dev/null 2>&1; then 17 | echo "! You don't have DKMS accessible in system." 18 | exit 1 19 | fi 20 | 21 | if [ ! -e dkms.conf ]; then 22 | echo "! You don't have DKMS configured for this module." 23 | exit 1 24 | fi 25 | 26 | MVERSION=`./version.sh` 27 | 28 | contains() { for e in "${@:2}"; do [[ "$e" = "$1" ]] && return 0; done; return 1; } 29 | 30 | D=() # to be list of installed versions 31 | OLDIFS="$IFS" 32 | IFS=$'\n' A=(`dkms status | grep ^ipt-netflow`) 33 | IFS="$OLDIFS" 34 | 35 | for i in "${A[@]}"; do 36 | z=($i) 37 | v=${z[1]} 38 | v=${v%,} 39 | v=${v%:} 40 | if ! contains "$v" "${D[@]}"; then 41 | D+=($v) 42 | fi 43 | done 44 | 45 | if [ ${#D[@]} -eq 1 ]; then 46 | # single version is already installed. 47 | if [ $D = "$MVERSION" ]; then 48 | echo "! You have same version of module already installed into DKMS." 49 | else 50 | echo "! You have different version of module installed into DKMS." 51 | fi 52 | if [ ! -d /usr/src/ipt-netflow-$D ]; then 53 | echo "! Can not find DKMS dir for it, that's plain weird." 54 | elif [ -e /usr/src/ipt-netflow-$D/.automatic ]; then 55 | echo "! That version was automatically installed by this script," 56 | echo "! thus, is safe to remove. No worries." 57 | else 58 | echo "! That version was manually installed by you." 59 | fi 60 | 61 | nodepmod= 62 | if grep -qs no-depmod `which dkms`; then 63 | nodepmod=--no-depmod 64 | fi 65 | echo "! Removing from dkms..." 66 | dkms $nodepmod remove ipt-netflow/$D --all 67 | 68 | if [ -d "/usr/src/ipt-netflow-$D" ]; then 69 | echo "! Removing source tree from /usr/src/ipt-netflow-$D" 70 | rm -rf "/usr/src/ipt-netflow-$D" 71 | fi 72 | 73 | elif [ ${#D[@]} -gt 1 ]; then 74 | # multiple versions are installed. 75 | echo "! You have multiple versions of module already installed in DKMS." 76 | echo "! Please remove them manually to avoid conflict." 77 | echo "! 'dkms status' output:" 78 | dkms status 79 | echo "! Suggested commands to remove them:" 80 | for i in ${D[@]}; do 81 | echo "! root# dkms remove ipt-netflow/$i --all" 82 | done 83 | exit 1 84 | fi 85 | 86 | if [ "$1" = --uninstall ]; then 87 | exit 0 88 | fi 89 | 90 | if [ "$PWD" = "/usr/src/ipt-netflow-$MVERSION" ]; then 91 | echo "! You are already in DKMS dir." 92 | dkms add -m ipt-netflow -v $MVERSION 93 | exit $? 94 | fi 95 | 96 | echo "! Installing $MVERSION into DKMS..." 97 | rm -rf /usr/src/ipt-netflow-$MVERSION 98 | 99 | mkdir -p /usr/src/ipt-netflow-$MVERSION 100 | cp -p *.[ch] Make* READ* conf* gen* irq* *.sh *.conf /usr/src/ipt-netflow-$MVERSION/ 101 | if [ -d .git ]; then 102 | cp -pr .git /usr/src/ipt-netflow-$MVERSION/ 103 | fi 104 | touch /usr/src/ipt-netflow-$MVERSION/.automatic 105 | 106 | dkms add -m ipt-netflow -v $MVERSION 107 | exit $? 108 | 109 | -------------------------------------------------------------------------------- /ipt_NETFLOW.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only 2 | * 3 | * This file is part of NetFlow exporting module. 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 2 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | */ 19 | 20 | #ifndef _IPT_NETFLOW_H 21 | #define _IPT_NETFLOW_H 22 | 23 | /* 24 | * Some tech info: 25 | * http://www.cisco.com/en/US/products/ps6601/prod_white_papers_list.html 26 | * http://www.cisco.com/en/US/products/sw/netmgtsw/ps1964/products_implementation_design_guide09186a00800d6a11.html 27 | */ 28 | 29 | #define NETFLOW5_RECORDS_MAX 30 30 | 31 | struct netflow5_record { 32 | __be32 s_addr; 33 | __be32 d_addr; 34 | __be32 nexthop; 35 | __be16 i_ifc; 36 | __be16 o_ifc; 37 | __be32 nr_packets; 38 | __be32 nr_octets; 39 | __be32 first_ms; 40 | __be32 last_ms; 41 | __be16 s_port; 42 | __be16 d_port; 43 | __u8 reserved; 44 | __u8 tcp_flags; 45 | __u8 protocol; 46 | __u8 tos; 47 | __be16 s_as; 48 | __be16 d_as; 49 | __u8 s_mask; 50 | __u8 d_mask; 51 | __u16 padding; 52 | } __attribute__ ((packed)); 53 | 54 | /* NetFlow v5 packet */ 55 | struct netflow5_pdu { 56 | __be16 version; 57 | __be16 nr_records; 58 | __be32 ts_uptime; /* ms */ 59 | __be32 ts_usecs; /* s */ 60 | __be32 ts_unsecs; /* ns */ 61 | __be32 seq; 62 | __u8 eng_type; 63 | __u8 eng_id; 64 | __u16 sampling; 65 | struct netflow5_record flow[NETFLOW5_RECORDS_MAX]; 66 | } __attribute__ ((packed)); 67 | #define NETFLOW5_HEADER_SIZE (sizeof(struct netflow5_pdu) - NETFLOW5_RECORDS_MAX * sizeof(struct netflow5_record)) 68 | 69 | #define IF_NAME_SZ IFNAMSIZ 70 | #define IF_DESC_SZ 32 71 | 72 | /* NetFlow v9 http://www.ietf.org/rfc/rfc3954.txt */ 73 | /* IPFIX http://www.iana.org/assignments/ipfix/ipfix.xhtml */ 74 | /* v9 elements are uppercased, IPFIX camel cased. */ 75 | #define one(id, name, len) name = id, 76 | #define two(id, a, b, len) \ 77 | one(id, a, len) \ 78 | one(id, b, len) 79 | #define Elements \ 80 | two(1, IN_BYTES, octetDeltaCount, 4) \ 81 | two(2, IN_PKTS, packetDeltaCount, 4) \ 82 | two(4, PROTOCOL, protocolIdentifier, 1) \ 83 | two(5, TOS, ipClassOfService, 1) \ 84 | two(6, TCP_FLAGS, tcpControlBits, 1) \ 85 | two(7, L4_SRC_PORT, sourceTransportPort, 2) \ 86 | two(8, IPV4_SRC_ADDR, sourceIPv4Address, 4) \ 87 | two(9, SRC_MASK, sourceIPv4PrefixLength, 1) \ 88 | two(10, INPUT_SNMP, ingressInterface, 2) \ 89 | two(11, L4_DST_PORT, destinationTransportPort, 2) \ 90 | two(12, IPV4_DST_ADDR, destinationIPv4Address, 4) \ 91 | two(13, DST_MASK, destinationIPv4PrefixLength, 1) \ 92 | two(14, OUTPUT_SNMP, egressInterface, 2) \ 93 | two(15, IPV4_NEXT_HOP, ipNextHopIPv4Address, 4) \ 94 | two(21, LAST_SWITCHED, flowEndSysUpTime, 4) \ 95 | two(22, FIRST_SWITCHED, flowStartSysUpTime, 4) \ 96 | one(25, minimumIpTotalLength, 2) \ 97 | one(26, maximumIpTotalLength, 2) \ 98 | two(27, IPV6_SRC_ADDR, sourceIPv6Address, 16) \ 99 | two(28, IPV6_DST_ADDR, destinationIPv6Address, 16) \ 100 | two(31, IPV6_FLOW_LABEL, flowLabelIPv6, 3) \ 101 | two(32, ICMP_TYPE, icmpTypeCodeIPv4, 2) \ 102 | two(33, MUL_IGMP_TYPE, igmpType, 1) \ 103 | two(40, TOTAL_BYTES_EXP, exportedOctetTotalCount, 8) \ 104 | two(41, TOTAL_PKTS_EXP, exportedMessageTotalCount, 8) \ 105 | two(42, TOTAL_FLOWS_EXP, exportedFlowRecordTotalCount, 8) \ 106 | two(48, FLOW_SAMPLER_ID, samplerId, 1) \ 107 | two(49, FLOW_SAMPLER_MODE, samplerMode, 1) \ 108 | two(50, FLOW_SAMPLER_RANDOM_INTERVAL, samplerRandomInterval, 2) \ 109 | one(52, minimumTTL, 1) \ 110 | one(53, maximumTTL, 1) \ 111 | two(56, SRC_MAC, sourceMacAddress, 6) \ 112 | two(57, DST_MAC, postDestinationMacAddress, 6) \ 113 | two(58, SRC_VLAN, vlanId, 2) \ 114 | two(60, IP_VERSION, ipVersion, 1) \ 115 | two(61, DIRECTION, flowDirection, 1) \ 116 | two(62, IPV6_NEXT_HOP, ipNextHopIPv6Address, 16) \ 117 | two(64, IPV6_OPTION_HEADERS, ipv6ExtensionHeaders, 2) \ 118 | two(70, MPLS_LABEL_1, mplsTopLabelStackSection, 3) \ 119 | two(71, MPLS_LABEL_2, mplsLabelStackSection2, 3) \ 120 | two(72, MPLS_LABEL_3, mplsLabelStackSection3, 3) \ 121 | two(73, MPLS_LABEL_4, mplsLabelStackSection4, 3) \ 122 | two(74, MPLS_LABEL_5, mplsLabelStackSection5, 3) \ 123 | two(75, MPLS_LABEL_6, mplsLabelStackSection6, 3) \ 124 | two(76, MPLS_LABEL_7, mplsLabelStackSection7, 3) \ 125 | two(77, MPLS_LABEL_8, mplsLabelStackSection8, 3) \ 126 | two(78, MPLS_LABEL_9, mplsLabelStackSection9, 3) \ 127 | two(79, MPLS_LABEL_10, mplsLabelStackSection10, 3) \ 128 | one(80, destinationMacAddress, 6) \ 129 | two(82, IF_NAME, interfaceName, IF_NAME_SZ) \ 130 | two(83, IF_DESC, interfaceDescription, IF_DESC_SZ) \ 131 | one(136, flowEndReason, 1) \ 132 | one(138, observationPointId, 4) \ 133 | one(139, icmpTypeCodeIPv6, 2) \ 134 | one(141, LineCardId, 4) \ 135 | one(142, portId, 4) \ 136 | one(143, meteringProcessId, 4) \ 137 | one(144, exportingProcessId, 4) \ 138 | one(145, TemplateId, 2) \ 139 | one(149, observationDomainId, 4) \ 140 | one(152, flowStartMilliseconds, 8) \ 141 | one(153, flowEndMilliseconds, 8) \ 142 | one(154, flowStartMicroseconds, 8) \ 143 | one(155, flowEndMicroseconds, 8) \ 144 | one(160, systemInitTimeMilliseconds, 8) \ 145 | one(163, observedFlowTotalCount, 8) \ 146 | one(164, ignoredPacketTotalCount, 8) \ 147 | one(165, ignoredOctetTotalCount, 8) \ 148 | one(166, notSentFlowTotalCount, 8) \ 149 | one(167, notSentPacketTotalCount, 8) \ 150 | one(168, notSentOctetTotalCount, 8) \ 151 | one(200, mplsTopLabelTTL, 1) \ 152 | one(201, mplsLabelStackLength, 1) \ 153 | one(202, mplsLabelStackDepth, 1) \ 154 | one(208, ipv4Options, 4) \ 155 | one(209, tcpOptions, 4) \ 156 | one(225, postNATSourceIPv4Address, 4) \ 157 | one(226, postNATDestinationIPv4Address, 4) \ 158 | one(227, postNAPTSourceTransportPort, 2) \ 159 | one(228, postNAPTDestinationTransportPort, 2) \ 160 | one(230, natEvent, 1) \ 161 | one(243, dot1qVlanId, 2) \ 162 | one(244, dot1qPriority, 1) \ 163 | one(245, dot1qCustomerVlanId, 2) \ 164 | one(246, dot1qCustomerPriority, 1) \ 165 | one(252, ingressPhysicalInterface, 2) \ 166 | one(253, egressPhysicalInterface, 2) \ 167 | one(256, ethernetType, 2) \ 168 | one(295, IPSecSPI, 4) \ 169 | one(300, observationDomainName, 128) \ 170 | one(302, selectorId, 1) \ 171 | one(309, samplingSize, 1) \ 172 | one(310, samplingPopulation, 2) \ 173 | one(318, selectorIdTotalPktsObserved, 8) \ 174 | one(319, selectorIdTotalPktsSelected, 8) \ 175 | one(323, observationTimeMilliseconds, 8) \ 176 | one(324, observationTimeMicroseconds, 8) \ 177 | one(325, observationTimeNanoseconds, 8) \ 178 | one(390, flowSelectorAlgorithm, 1) \ 179 | one(394, selectorIDTotalFlowsObserved, 8) \ 180 | one(395, selectorIDTotalFlowsSelected, 8) \ 181 | one(396, samplingFlowInterval, 1) \ 182 | one(397, samplingFlowSpacing, 2) 183 | 184 | enum { 185 | Elements 186 | }; 187 | #undef one 188 | #undef two 189 | 190 | enum { 191 | FLOWSET_TEMPLATE = 0, 192 | FLOWSET_OPTIONS = 1, 193 | IPFIX_TEMPLATE = 2, 194 | IPFIX_OPTIONS = 3, 195 | FLOWSET_DATA_FIRST = 256, 196 | }; 197 | 198 | enum { /* v9 scopes */ 199 | V9_SCOPE_SYSTEM = 1, 200 | V9_SCOPE_INTERFACE = 2, 201 | V9_SCOPE_LINECARD = 3, 202 | V9_SCOPE_CACHE = 4, 203 | V9_SCOPE_TEMPLATE = 5, 204 | }; 205 | 206 | struct flowset_template { 207 | __be16 flowset_id; 208 | __be16 length; /* (bytes) */ 209 | __be16 template_id; 210 | __be16 field_count; /* (items) */ 211 | } __attribute__ ((packed)); 212 | 213 | struct flowset_data { 214 | __be16 flowset_id; /* corresponds to template_id */ 215 | __be16 length; /* (bytes) */ 216 | } __attribute__ ((packed)); 217 | 218 | /* http://tools.ietf.org/html/rfc3954#section-6.1 */ 219 | struct flowset_opt_tpl_v9 { 220 | __be16 flowset_id; 221 | __be16 length; 222 | __be16 template_id; 223 | __be16 scope_len; /* (bytes) */ 224 | __be16 opt_len; /* (bytes) */ 225 | } __attribute__ ((packed)); 226 | 227 | /* http://tools.ietf.org/html/rfc5101#section-3.4.2.2 */ 228 | struct flowset_opt_tpl_ipfix { 229 | __be16 flowset_id; 230 | __be16 length; 231 | __be16 template_id; 232 | __be16 field_count; /* total (items) */ 233 | __be16 scope_count; /* (items) must not be zero */ 234 | } __attribute__ ((packed)); 235 | 236 | /* NetFlow v9 packet. */ 237 | struct netflow9_pdu { 238 | __be16 version; 239 | __be16 nr_records; /* (items) */ 240 | __be32 sys_uptime_ms; 241 | __be32 export_time_s; 242 | __be32 seq; 243 | __be32 source_id; /* Exporter Observation Domain */ 244 | __u8 data[1400]; 245 | } __attribute__ ((packed)); 246 | 247 | /* IPFIX packet. */ 248 | struct ipfix_pdu { 249 | __be16 version; 250 | __be16 length; /* (bytes) */ 251 | __be32 export_time_s; 252 | __be32 seq; 253 | __be32 odomain_id; /* Observation Domain ID */ 254 | __u8 data[1400]; 255 | } __attribute__ ((packed)); 256 | 257 | /* Maximum bytes flow can have, after it's reached flow will become 258 | * not searchable and will be exported soon. */ 259 | #define FLOW_FULL_WATERMARK 0xffefffff 260 | 261 | #define EXTRACT_SPI(tuple) ((tuple.s_port << 16) | tuple.d_port) 262 | #define SAVE_SPI(tuple, spi) { tuple.s_port = spi >> 16; \ 263 | tuple.d_port = spi; } 264 | #define MAX_VLAN_TAGS 2 265 | 266 | /* hashed data which identify unique flow */ 267 | /* 16+16 + 2+2 + 2+1+1+1 = 41 */ 268 | struct ipt_netflow_tuple { 269 | union nf_inet_addr src; 270 | union nf_inet_addr dst; 271 | __be16 s_port; // Network byte order 272 | __be16 d_port; // -"- 273 | #ifdef MPLS_DEPTH 274 | __be32 mpls[MPLS_DEPTH]; /* Network byte order */ 275 | #endif 276 | __u16 i_ifc; // Host byte order 277 | #ifdef ENABLE_VLAN 278 | __be16 tag[MAX_VLAN_TAGS]; // Network byte order (outer tag first) 279 | #endif 280 | __u8 protocol; 281 | __u8 tos; 282 | __u8 l3proto; 283 | #ifdef ENABLE_MAC 284 | __u8 h_dst[ETH_ALEN]; 285 | __u8 h_src[ETH_ALEN]; 286 | #endif 287 | } __attribute__ ((packed)); 288 | 289 | /* hlist[2] + tuple[]: 8+8 + 41 = 57 (less than usual cache line, 64) */ 290 | struct ipt_netflow { 291 | struct hlist_node hlist; // hashtable search chain 292 | 293 | /* unique per flow data (hashed, NETFLOW_TUPLE_SIZE) */ 294 | struct ipt_netflow_tuple tuple; 295 | 296 | /* volatile data */ 297 | union nf_inet_addr nh; 298 | #if defined(ENABLE_MAC) || defined(ENABLE_VLAN) 299 | __be16 ethernetType; /* Network byte order */ 300 | #endif 301 | __u16 o_ifc; 302 | #ifdef ENABLE_PHYSDEV 303 | __u16 i_ifphys; 304 | __u16 o_ifphys; 305 | #endif 306 | #ifdef SNMP_RULES 307 | __u16 i_ifcr; /* translated interface numbers*/ 308 | __u16 o_ifcr; 309 | #endif 310 | __u8 s_mask; 311 | __u8 d_mask; 312 | __u8 tcp_flags; /* `OR' of all tcp flags */ 313 | __u8 flowEndReason; 314 | #ifdef ENABLE_DIRECTION 315 | __u8 hooknumx; /* hooknum + 1 */ 316 | #endif 317 | /* flow statistics */ 318 | u_int32_t nr_packets; 319 | u_int32_t nr_bytes; 320 | #ifdef ENABLE_SAMPLER 321 | unsigned int sampler_count; /* for deterministic sampler only */ 322 | #endif 323 | union { 324 | struct { 325 | unsigned long first; 326 | unsigned long last; 327 | } ts; 328 | ktime_t ts_obs; 329 | } _ts_un; 330 | #define nf_ts_first _ts_un.ts.first 331 | #define nf_ts_last _ts_un.ts.last 332 | #define nf_ts_obs _ts_un.ts_obs 333 | u_int32_t flow_label; /* IPv6 */ 334 | u_int32_t options; /* IPv4(16) & IPv6(32) Options */ 335 | u_int32_t tcpoptions; 336 | #ifdef CONFIG_NF_NAT_NEEDED 337 | __be32 s_as; 338 | __be32 d_as; 339 | struct nat_event *nat; 340 | #endif 341 | union { 342 | struct list_head list; /* all flows in ipt_netflow_list */ 343 | #ifdef HAVE_LLIST 344 | struct llist_node llnode; /* purged flows */ 345 | #endif 346 | } _flow_list; 347 | #define flows_list _flow_list.list 348 | #define flows_llnode _flow_list.llnode 349 | }; 350 | 351 | #ifdef CONFIG_NF_NAT_NEEDED 352 | enum { 353 | NAT_CREATE = 1, NAT_DESTROY = 2, NAT_POOLEXHAUSTED = 3 354 | }; 355 | struct nat_event { 356 | struct list_head list; 357 | struct { 358 | __be32 s_addr; 359 | __be32 d_addr; 360 | __be16 s_port; 361 | __be16 d_port; 362 | } pre, post; 363 | ktime_t ts_ktime; 364 | unsigned long ts_jiffies; 365 | __u8 protocol; 366 | __u8 nat_event; 367 | }; 368 | #define IS_DUMMY_FLOW(nf) (nf->nat) 369 | #else 370 | #define IS_DUMMY_FLOW(nf) 0 371 | #endif 372 | 373 | static inline int ipt_netflow_tuple_equal(const struct ipt_netflow_tuple *t1, 374 | const struct ipt_netflow_tuple *t2) 375 | { 376 | return (!memcmp(t1, t2, sizeof(struct ipt_netflow_tuple))); 377 | } 378 | 379 | struct ipt_netflow_sock { 380 | struct list_head list; 381 | struct socket *sock; 382 | struct sockaddr_storage addr; // destination 383 | struct sockaddr_storage saddr; // source 384 | char sdev[IFNAMSIZ]; // source device 385 | atomic_t wmem_peak; // sk_wmem_alloc peak value 386 | unsigned int err_connect; // connect errors 387 | unsigned int err_full; // socket filled error 388 | unsigned int err_other; // other socket errors 389 | unsigned int err_cberr; // async errors, icmp 390 | unsigned int pkt_exp; // pkts expoted to this dest 391 | u64 bytes_exp; // bytes -"- 392 | u64 bytes_exp_old; // for rate calculation 393 | unsigned int bytes_rate; // bytes per second 394 | unsigned int pkt_sent; // pkts sent to this dest 395 | unsigned int pkt_fail; // pkts failed to send to this dest 396 | }; 397 | 398 | struct netflow_aggr_n { 399 | struct list_head list; 400 | atomic_t usage; 401 | __u32 mask; 402 | __u32 addr; 403 | __u32 aggr_mask; 404 | __u8 prefix; 405 | }; 406 | 407 | struct netflow_aggr_p { 408 | struct list_head list; 409 | atomic_t usage; 410 | __u16 port1; 411 | __u16 port2; 412 | __u16 aggr_port; 413 | }; 414 | 415 | #define NETFLOW_STAT_INC(count) (__get_cpu_var(ipt_netflow_stat).count++) 416 | #define NETFLOW_STAT_ADD(count, val) (__get_cpu_var(ipt_netflow_stat).count += (unsigned long long)val) 417 | #define NETFLOW_STAT_SET(count, val) (__get_cpu_var(ipt_netflow_stat).count = (unsigned long long)val) 418 | #define NETFLOW_STAT_TS(count) \ 419 | do { \ 420 | ktime_t kts = ktime_get_real(); \ 421 | if (!(__get_cpu_var(ipt_netflow_stat)).count.first_tv64) \ 422 | __get_cpu_var(ipt_netflow_stat).count.first = kts; \ 423 | __get_cpu_var(ipt_netflow_stat).count.last = kts; \ 424 | } while (0); 425 | 426 | #define NETFLOW_STAT_INC_ATOMIC(count) \ 427 | do { \ 428 | preempt_disable(); \ 429 | (__get_cpu_var(ipt_netflow_stat).count++); \ 430 | preempt_enable(); \ 431 | } while (0); 432 | 433 | #define NETFLOW_STAT_ADD_ATOMIC(count, val) \ 434 | do { \ 435 | preempt_disable(); \ 436 | (__get_cpu_var(ipt_netflow_stat).count += (unsigned long long)val); \ 437 | preempt_enable(); \ 438 | } while (0); 439 | #define NETFLOW_STAT_READ(count) ({ \ 440 | unsigned int _tmp = 0, _cpu; \ 441 | for_each_present_cpu(_cpu) \ 442 | _tmp += per_cpu(ipt_netflow_stat, _cpu).count; \ 443 | _tmp; \ 444 | }) 445 | 446 | struct duration { 447 | ktime_t first; 448 | ktime_t last; 449 | }; 450 | 451 | /* statistics */ 452 | struct ipt_netflow_stat { 453 | u64 searched; // hash stat 454 | u64 found; // hash stat 455 | u64 notfound; // hash stat (new flows) 456 | u64 pkt_total; // packets metered 457 | u64 traf_total; // traffic metered 458 | #ifdef ENABLE_PROMISC 459 | u64 pkt_promisc; // how much packets passed promisc code 460 | u64 pkt_promisc_drop; // how much packets discarded 461 | #endif 462 | /* above is grouped for cache */ 463 | unsigned int truncated; // packets stat (drop) 464 | unsigned int frags; // packets stat (drop) 465 | unsigned int maxflows_err; // maxflows reached (drop) 466 | unsigned int alloc_err; // failed to allocate memory (drop & lost) 467 | struct duration drop; 468 | unsigned int send_success; // sendmsg() ok 469 | unsigned int send_failed; // sendmsg() failed 470 | unsigned int sock_cberr; // socket error callback called (got icmp refused) 471 | unsigned int exported_rate; // netflow traffic itself 472 | u64 exported_pkt; // netflow traffic itself 473 | u64 exported_flow; // netflow traffic itself 474 | u64 exported_traf; // netflow traffic itself 475 | u64 exported_trafo; // netflow traffic itself 476 | u64 pkt_total_prev; // packets metered previous interval 477 | u32 pkt_total_rate; // packet rate for this cpu 478 | u64 pkt_drop; // packets not metered 479 | u64 traf_drop; // traffic not metered 480 | u64 flow_lost; // flows not sent to collector 481 | u64 pkt_lost; // packets not sent to collector 482 | u64 traf_lost; // traffic not sent to collector 483 | struct duration lost; 484 | u64 pkt_out; // packets out of the hash 485 | u64 traf_out; // traffic out of the hash 486 | #ifdef ENABLE_SAMPLER 487 | u64 pkts_observed; // sampler stat 488 | u64 pkts_selected; // sampler stat 489 | #endif 490 | u64 old_searched; // previous hash stat 491 | u64 old_found; // for calculation per cpu metric 492 | u64 old_notfound; 493 | int metric; // one minute ewma of hash efficiency 494 | }; 495 | 496 | #endif 497 | /* vim: set sw=8: */ 498 | -------------------------------------------------------------------------------- /irqtop: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | # SPDX-License-Identifier: GPL-2.0-only 3 | # 4 | # Observe irq and softirq in top fashion 5 | # (c) 2014 6 | # License: GPL-2.0-only. 7 | 8 | require 'getoptlong' 9 | require 'curses' 10 | require 'stringio' 11 | 12 | @imode = :both 13 | @omode = :table 14 | @color = true 15 | @showrps = false 16 | 17 | GetoptLong.new( 18 | ["--help", "-h", GetoptLong::NO_ARGUMENT], 19 | ["--batch", "-b", GetoptLong::NO_ARGUMENT], 20 | ["--delay", "-d", GetoptLong::REQUIRED_ARGUMENT], 21 | ["--top", "-t", GetoptLong::NO_ARGUMENT], 22 | ["--table", "-x", GetoptLong::NO_ARGUMENT], 23 | ["--soft", "-s", GetoptLong::NO_ARGUMENT], 24 | ["--softirq", GetoptLong::NO_ARGUMENT], 25 | ["--softirqs", GetoptLong::NO_ARGUMENT], 26 | ["--irq", "-i", GetoptLong::NO_ARGUMENT], 27 | ["--irqs", GetoptLong::NO_ARGUMENT], 28 | ["--reverse", "-r", GetoptLong::NO_ARGUMENT], 29 | ["--nocolor", "-C", GetoptLong::NO_ARGUMENT], 30 | ["--eth", "-e", "--pps", GetoptLong::NO_ARGUMENT], 31 | ["--rps", "-R", "--xps", GetoptLong::NO_ARGUMENT] 32 | ).each do |opt, arg| 33 | case opt 34 | when '--help' 35 | puts " Shows interrupt rates (per second) per cpu." 36 | puts " Also shows irq affinity ('.' for disabled cpus)," 37 | puts " and rps/xps affinity ('+' rx, '-' tx, '*' tx/rx)." 38 | puts " Can show packet rate per eth queue." 39 | puts 40 | puts " Usage: #{$0} [-h] [-d #{@delay}] [-b] [-t|-x] [-i|-s] [-r]" 41 | puts " -d --delay=n refresh interval" 42 | puts " -s --softirq select softirqs only" 43 | puts " -i --irq select hardware irqs only" 44 | puts " -e --eth show extra eth stats (from ethtool)" 45 | puts " -R --rps enable display of rps/xps" 46 | puts " -x --table output in table mode (default)" 47 | puts " -t --top output in flat top mode" 48 | puts " -b --batch output non-interactively" 49 | puts " -r --reverse reverse sort order" 50 | puts " -C --nocolor disable colors" 51 | puts 52 | puts " Rates marked as '.' is forbidden by smp_affinity mask." 53 | exit 0 54 | when '--reverse' 55 | @reverse = !@reverse 56 | when '--batch' 57 | @batch = true 58 | @reverse = !@reverse if @omode == :top 59 | when '--delay' 60 | @delay = arg.to_i 61 | when '--top' 62 | @omode = :top 63 | when '--table' 64 | @omode = :table 65 | when /--irq/ 66 | @imode = :irq 67 | when /--soft/ 68 | @imode = :soft 69 | when /--pps/ 70 | @pps = true 71 | when /--nocolor/ 72 | @color = false 73 | when /--rps/ 74 | @showrps = !@showrps 75 | end 76 | end 77 | if !@delay && ARGV[0].to_f > 0 78 | @delay = ARGV.shift.to_f 79 | else 80 | @delay = 5 81 | end 82 | @count = ARGV.shift.to_f if ARGV[0].to_i > 0 83 | 84 | def read_table(tag, file) 85 | @cpus = [] 86 | lines = IO.readlines(file) 87 | @cpus = lines[0].scan(/CPU\d+/) 88 | @icpus = @cpus if tag == 'i' 89 | lines[2..-1].each do |li| 90 | irq, stat, desc = li.match(/^\s*(\S+):((?:\s+\d+)+)(.*)$/).captures 91 | stat = stat.scan(/\d+/) 92 | @irqs << [tag, irq, desc] 93 | stat.each_with_index do |val, i| 94 | # interruptsN, 's|i', irq'N', 'cpuX', 'descr...' 95 | @stats << [val.to_i, tag, irq, @cpus[i], desc.strip] 96 | end 97 | end 98 | end 99 | 100 | def read_procstat 101 | @cstat = {} 102 | lines = IO.readlines("/proc/stat").grep(/^cpu\d+ /) 103 | lines.each do |li| 104 | c, *d = li.split(" ") 105 | d = d.map {|e| e.to_i} 106 | @cstat[c] = d 107 | end 108 | end 109 | 110 | def read_affinity 111 | @aff = {} 112 | Dir.glob("/proc/irq/*/smp_affinity").each do |af| 113 | irq = af[%r{\d+}].to_i 114 | a = IO.read(af).strip.to_i(16) 115 | @aff[irq] = a 116 | end 117 | end 118 | 119 | # list ethernet devices 120 | def net_devices_pci 121 | Dir['/sys/class/net/*'].reject do |f| 122 | f += "/device" unless File.symlink?(f) 123 | if File.symlink?(f) 124 | !(File.readlink(f) =~ %r{devices/pci}) 125 | else 126 | false 127 | end 128 | end.map {|f| File.basename(f)} 129 | end 130 | 131 | @devlist = net_devices_pci 132 | @devre = Regexp.union(@devlist) 133 | def get_rps(desc) 134 | @rps = @xps = 0 135 | return unless @showrps 136 | return if @devlist.empty? 137 | dev = desc[/\b(#{@devre})\b/, 1] 138 | return unless dev 139 | return unless desc =~ /-(tx|rx)+-\d+/i 140 | qnr = desc[/-(\d+)\s*$/, 1] 141 | return unless qnr 142 | begin 143 | @rps = IO.read("/sys/class/net/#{dev}/queues/rx-#{qnr}/rps_cpus").hex if desc =~ /rx/i 144 | @xps = IO.read("/sys/class/net/#{dev}/queues/tx-#{qnr}/xps_cpus").hex if desc =~ /tx/i 145 | rescue 146 | end 147 | end 148 | 149 | def calc_rps(cpu) 150 | m = 0 151 | m |= 1 if @rps & (1 << cpu) != 0 152 | m |= 2 if @xps & (1 << cpu) != 0 153 | " +-*".slice(m, 1) 154 | end 155 | 156 | # ethtool -S eth0 157 | def ethtool_grab_stat(dev = nil) 158 | unless dev 159 | @esto = @est if @est 160 | @est = Hash.new { |h,k| h[k] = Hash.new(&h.default_proc) } 161 | @devlist = net_devices_pci 162 | @devre = Regexp.union(@devlist) 163 | # own time counter because this stat could be paused 164 | @ehts = @ets if @ets 165 | @ets = @ts 166 | @edt = @ets - @ehts if @ehts 167 | @devlist.each {|e| ethtool_grab_stat(e)} 168 | return 169 | end 170 | h = Hash.new {|k,v| k[v] = Array.new} 171 | t = `ethtool -S #{dev} 2>/dev/null` 172 | return if t == '' 173 | t.split("\n").map { |e| 174 | e.split(':') 175 | }.reject { |e| 176 | !e[1] 177 | }.each { |k,v| 178 | k.strip! 179 | v = v.strip.to_i 180 | if k =~ /^.x_queue_(\d+)_/ 181 | t = k.split('_', 4) 182 | qdir = t[0] 183 | qnr = t[2] 184 | qk = t[3] 185 | @est[dev][qdir][qnr][qk] = v 186 | else 187 | @est[dev][k] = v 188 | end 189 | } 190 | end 191 | 192 | def e_queue_stat(dev, qdir, qnr, k) 193 | n = @est[dev][qdir][qnr][k] 194 | o = @esto[dev][qdir][qnr][k] 195 | d = (n - o) / @edt 196 | if d > 0 197 | "%s:%d" % [qdir, d] 198 | else 199 | nil 200 | end 201 | end 202 | 203 | def e_dev_stat(dev, k, ks) 204 | n = @est[dev][k] 205 | o = @esto[dev][k] 206 | r = (n - o) / @edt 207 | ks = k unless ks 208 | "%s:%d" % [ks, r] 209 | end 210 | 211 | def e_queue_stat_err(dev, qdir, qnr) 212 | r = [] 213 | ek = @est[dev][qdir][qnr].keys.reject{|e| e =~ /^(bytes|packets)$/} 214 | ek.each do |k| 215 | n = @est[dev][qdir][qnr][k] 216 | o = @esto[dev][qdir][qnr][k] 217 | d = n - o 218 | r << "%s_%s:%d" % [qdir, k, d] if d.to_i > 0 219 | end 220 | r 221 | end 222 | 223 | # this is not rate 224 | def e_dev_stat_sum(dev, rk, ks) 225 | ek = @est[dev].keys.reject{|ek| !(ek =~ rk)} 226 | n = ek.inject(0) {|sum,k| sum += @est[dev][k].to_i} 227 | o = ek.inject(0) {|sum,k| sum += @esto[dev][k].to_i rescue 0} 228 | r = (n - o) 229 | if r > 0 230 | "%s:%d" % [ks, r] 231 | else 232 | nil 233 | end 234 | end 235 | 236 | def print_ethstat(desc) 237 | return if @devlist.empty? 238 | dev = desc[/\b(#{@devre})\b/, 1] 239 | return unless dev 240 | unless @esto && @est 241 | print ' []' 242 | return 243 | end 244 | t = [] 245 | if desc =~ /-(tx|rx)+-\d+/i 246 | qnr = desc[/-(\d+)\s*$/, 1] 247 | if qnr 248 | if desc =~ /rx/i 249 | t << e_queue_stat(dev, "rx", qnr, "packets") 250 | t += e_queue_stat_err(dev, "rx", qnr) 251 | end 252 | if desc =~ /tx/i 253 | t << e_queue_stat(dev, "tx", qnr, "packets") 254 | t += e_queue_stat_err(dev, "tx", qnr) 255 | end 256 | end 257 | else 258 | t << e_dev_stat(dev, "rx_packets", 'rx') 259 | t << e_dev_stat(dev, "tx_packets", 'tx') 260 | t << e_dev_stat_sum(dev, /_err/, 'err') 261 | t << e_dev_stat_sum(dev, /_drop/, 'drop') 262 | end 263 | t.delete(nil) 264 | print ' [' + t.join(' ') + ']' 265 | end 266 | 267 | def grab_stat 268 | # @h[istorical] 269 | @hstats = @stats 270 | @hcstat = @cstat 271 | @hts = @ts 272 | 273 | @stats = [] 274 | @irqs = [] 275 | @ts = Time.now 276 | @dt = @ts - @hts if @hts 277 | 278 | read_table 'i', "/proc/interrupts" 279 | read_table 's', "/proc/softirqs" 280 | read_affinity 281 | read_procstat 282 | ethtool_grab_stat if @pps 283 | end 284 | 285 | def calc_speed 286 | s = [] 287 | # calc speed 288 | h = Hash.new(0) 289 | @hstats.each do |v, t, i, c, d| 290 | h[[t, i, c]] = v 291 | end 292 | # output 293 | @h = {} 294 | @t = Hash.new(0) # rate per cpu 295 | @w = Hash.new(0) # irqs per irqN 296 | @s = @stats.map do |v, t, i, c, d| 297 | rate = (v - h[[t, i, c]]) / @dt 298 | @t[c] += rate if t == 'i' 299 | @w[[t, i]] += (v - h[[t, i, c]]) 300 | @h[[t, i, c]] = rate 301 | [rate, v, t, i, c, d] 302 | end 303 | end 304 | 305 | def calc_cpu 306 | @cBusy = Hash.new(0) 307 | @cHIrq = Hash.new(0) 308 | @cSIrq = Hash.new(0) 309 | # user, nice, system, [3] idle, [4] iowait, irq, softirq, etc. 310 | @cstat.each do |c, d| 311 | d = d.zip(@hcstat[c]).map {|a, b| a - b} 312 | c = c.upcase 313 | sum = d.reduce(:+) 314 | @cBusy[c] = 100 - (d[3] + d[4]).to_f / sum * 100 315 | @cHIrq[c] = (d[5]).to_f / sum * 100 316 | @cSIrq[c] = (d[6]).to_f / sum * 100 317 | end 318 | end 319 | 320 | def show_top 321 | @s.sort!.reverse! 322 | @s.reverse! if @reverse 323 | rej = nil 324 | rej = 's' if @imode == :irq 325 | rej = 'i' if @imode == :soft 326 | @s.each do |s, v, t, i, c, d| 327 | next if t == rej 328 | if s > 0 329 | print "%9.1f %s %s <%s> %s" % [s, c.downcase, t, i, d] 330 | print_ethstat(d) if @pps 331 | puts 332 | end 333 | end 334 | end 335 | 336 | @ifilter = {} 337 | def show_interrupts 338 | maxlen = 7 339 | @irqs.reverse! if @reverse 340 | print "%s %*s " % [" ", maxlen, " "] 341 | @icpus.each { |c| print " %6s" % c } 342 | puts 343 | 344 | # load 345 | print "%*s: " % [maxlen + 2, "cpuUtil"] 346 | @icpus.each { |c| print " %6.1f" % @cBusy[c] } 347 | puts " total CPU utilization %" 348 | # 349 | print "%*s: " % [maxlen + 2, "%irq"] 350 | @icpus.each { |c| print " %6.1f" % @cHIrq[c] } 351 | puts " hardware IRQ CPU util%" 352 | print "%*s: " % [maxlen + 2, "%sirq"] 353 | @icpus.each { |c| print " %6.1f" % @cSIrq[c] } 354 | puts " software IRQ CPU util%" 355 | 356 | # total 357 | print "%*s: " % [maxlen + 2, "irqTotal"] 358 | @icpus.each { |c| print " %6d" % @t[c] } 359 | puts " total hardware IRQs" 360 | 361 | rej = nil 362 | rej = 's' if @imode == :irq 363 | rej = 'i' if @imode == :soft 364 | @irqs.each do |t, i, desc| 365 | next if t == rej 366 | 367 | # include incrementally and all eth 368 | unless @ifilter[[t, i]] || @showall 369 | next unless @w[[t, i]] > 0 || desc =~ /eth/ 370 | @ifilter[[t, i]] = true 371 | end 372 | 373 | print "%s %*s: " % [t.to_s, maxlen, i.slice(0, maxlen)] 374 | rps = get_rps(desc) 375 | @icpus.each do |c| 376 | cpu = c[/\d+/].to_i 377 | aff = @aff[i.to_i] 378 | off = ((aff & 1 << cpu) ==0)? true : false if aff 379 | fla = calc_rps(cpu) 380 | begin 381 | v = @h[[t, i, c]] 382 | if v > 0 || !off 383 | print "%6d%c" % [v, fla] 384 | elsif aff 385 | print "%6s%c" % [".", fla] 386 | end 387 | rescue 388 | end 389 | end 390 | print desc 391 | print_ethstat(desc) if @pps 392 | puts 393 | end 394 | end 395 | 396 | def select_output 397 | if @omode == :top 398 | show_top 399 | else 400 | show_interrupts 401 | end 402 | end 403 | 404 | def curses_choplines(text) 405 | cols = Curses.cols - 1 406 | rows = Curses.lines - 2 407 | lines = text.split("\n").map {|e| e.slice(0, cols)}.slice(0, rows) 408 | text = lines.join("\n") 409 | text << "\n" * (rows - lines.size) if lines.size < rows 410 | text 411 | end 412 | 413 | def show_help 414 | puts "irqtop help:" 415 | puts 416 | puts " In table view, cells marked with '.' mean this hw irq is" 417 | puts " disabled via /proc/irq//smp_affinity" 418 | puts " Interactive keys:" 419 | puts " i Toggle (hardware) irqs view" 420 | puts " s Toggle software irqs (softirqs) view" 421 | puts " e Show eth stat per queue" 422 | puts " R Show rps/xps affinity" 423 | puts " t Flat top display mode" 424 | puts " x Table display mode" 425 | puts " r Reverse rows order" 426 | puts " c Toggle colors (for eth)" 427 | puts " a Show lines with zero rate (all)" 428 | puts " A Clear lines with zero rates" 429 | puts " . Pause screen updating" 430 | puts " h,? This help screen" 431 | puts " q Quit." 432 | puts " Any other key will update display." 433 | puts 434 | puts "Press any key to continue." 435 | end 436 | 437 | hostname = `hostname`.strip 438 | # 439 | grab_stat 440 | sleep 0.5 441 | 442 | COLOR_GREEN = "\033[0;32m" 443 | COLOR_YELLOW = "\033[0;33m" 444 | COLOR_CYAN = "\033[0;36m" 445 | COLOR_RED = "\033[0;31m" 446 | COLOR_OFF = "\033[m" 447 | def tty_printline(t) 448 | latr = nil # line color 449 | if t =~ /-rx-/ 450 | latr = COLOR_GREEN 451 | elsif t =~ /-tx-/ 452 | latr = COLOR_YELLOW 453 | elsif t =~ /\beth/ 454 | latr = COLOR_CYAN 455 | end 456 | print latr if latr 457 | 458 | if t =~ /cpuUtil:|irq:|sirq:/ 459 | # colorize percentage values 460 | t.scan(/\s+\S+/) do |e| 461 | eatr = nil 462 | if e =~ /^\s*[\d.]+$/ 463 | if e.to_i >= 90 464 | eatr = COLOR_RED 465 | elsif e.to_i <= 10 466 | eatr = COLOR_GREEN 467 | else 468 | eatr = COLOR_YELLOW 469 | end 470 | end 471 | print eatr if eatr 472 | print e 473 | print (latr)? latr : COLOR_OFF if eatr 474 | end 475 | elsif latr && t =~ / \[[^\]]+\]$/ 476 | # colorize eth stats 477 | print $` 478 | print COLOR_OFF if latr 479 | $&.scan(/(.*?)(\w+)(:)(\d+)/) do |e| 480 | eatr = nil 481 | case e[1] 482 | when 'rx' 483 | eatr = COLOR_GREEN 484 | when 'tx' 485 | eatr = COLOR_YELLOW 486 | else 487 | eatr = COLOR_RED 488 | end 489 | eatr = nil if e[3].to_i == 0 490 | 491 | print e[0] 492 | print eatr if eatr 493 | print e[1..-1].join 494 | print (latr)? latr : COLOR_OFF if eatr 495 | end 496 | print $' 497 | else 498 | print t 499 | end 500 | 501 | print COLOR_OFF if latr 502 | puts 503 | end 504 | def tty_output 505 | if @color 506 | $stdout = StringIO.new 507 | yield 508 | $stdout.rewind 509 | txt = $stdout.read 510 | $stdout = STDOUT 511 | 512 | txt.split("\n", -1).each do |li| 513 | tty_printline(li) 514 | end 515 | else 516 | yield 517 | end 518 | end 519 | 520 | if @batch 521 | @color = @color && $stdout.tty? 522 | loop do 523 | grab_stat 524 | calc_speed 525 | calc_cpu 526 | puts "#{hostname} - irqtop - #{Time.now}" 527 | tty_output { 528 | select_output 529 | } 530 | $stdout.flush 531 | break if @count && (@count -= 1) == 0 532 | sleep @delay 533 | end 534 | exit 0 535 | end 536 | 537 | Curses.init_screen 538 | Curses.start_color 539 | Curses.cbreak 540 | Curses.noecho 541 | Curses.nonl 542 | Curses.init_pair(1, Curses::COLOR_GREEN, Curses::COLOR_BLACK); 543 | Curses.init_pair(2, Curses::COLOR_YELLOW, Curses::COLOR_BLACK); 544 | Curses.init_pair(3, Curses::COLOR_CYAN, Curses::COLOR_BLACK); 545 | Curses.init_pair(4, Curses::COLOR_RED, Curses::COLOR_BLACK); 546 | $stdscr = Curses.stdscr 547 | $stdscr.keypad(true) 548 | 549 | def curses_printline(t) 550 | latr = nil # line color 551 | if t =~ /-rx-/ 552 | latr = Curses.color_pair(1) 553 | elsif t =~ /-tx-/ 554 | latr = Curses.color_pair(2) 555 | elsif t =~ /\beth/ 556 | latr = Curses.color_pair(3) 557 | end 558 | $stdscr.attron(latr) if latr 559 | 560 | if t =~ /cpuUtil:|irq:|sirq:/ 561 | # colorize percentage values 562 | t.scan(/\s+\S+/) do |e| 563 | eatr = nil 564 | if e =~ /^\s*[\d.]+$/ 565 | if e.to_i >= 90 566 | eatr = Curses.color_pair(4) 567 | elsif e.to_i <= 10 568 | eatr = Curses.color_pair(1) 569 | else 570 | eatr = Curses.color_pair(2) 571 | end 572 | end 573 | $stdscr.attron(eatr) if eatr 574 | $stdscr.addstr("#{e}") 575 | $stdscr.attroff(eatr) if eatr 576 | end 577 | elsif latr && t =~ / \[[^\]]+\]$/ 578 | # colorize eth stats 579 | $stdscr.addstr($`) 580 | $stdscr.attroff(latr) if latr 581 | $&.scan(/(.*?)(\w+)(:)(\d+)/) do |e| 582 | eatr = nil 583 | case e[1] 584 | when 'rx' 585 | eatr = Curses.color_pair(1) 586 | when 'tx' 587 | eatr = Curses.color_pair(2) 588 | else 589 | eatr = Curses.color_pair(4) 590 | end 591 | eatr = nil if e[3].to_i == 0 592 | 593 | $stdscr.addstr(e[0]) 594 | $stdscr.attron(eatr) if eatr 595 | $stdscr.addstr(e[1..-1].join) 596 | $stdscr.attroff(eatr) if eatr 597 | end 598 | $stdscr.addstr($' + "\n") 599 | else 600 | $stdscr.addstr("#{t}\n") 601 | end 602 | 603 | $stdscr.attroff(latr) if latr 604 | end 605 | 606 | def curses_output 607 | $stdout = StringIO.new 608 | yield 609 | $stdout.rewind 610 | text = $stdout.read 611 | $stdout = STDOUT 612 | txt = curses_choplines(text) 613 | if @color 614 | txt.split("\n", -1).each_with_index do |li, i| 615 | $stdscr.setpos(i, 0) 616 | curses_printline(li) 617 | end 618 | else 619 | $stdscr.setpos(0, 0) 620 | $stdscr.addstr(txt) 621 | end 622 | $stdscr.setpos(1, 0) 623 | Curses.refresh 624 | end 625 | 626 | def curses_enter(text, echo = true) 627 | $stdscr.setpos(1, 0) 628 | $stdscr.addstr(text + "\n") 629 | $stdscr.setpos(1, 0) 630 | Curses.attron(Curses::A_BOLD) 631 | $stdscr.addstr(text) 632 | Curses.attroff(Curses::A_BOLD) 633 | Curses.refresh 634 | Curses.echo if echo 635 | Curses.timeout = -1 636 | line = Curses.getstr 637 | Curses.noecho 638 | line 639 | end 640 | 641 | loop do 642 | grab_stat 643 | calc_speed 644 | calc_cpu 645 | 646 | curses_output { 647 | puts "#{hostname} - irqtop - #{Time.now}" 648 | select_output 649 | } 650 | 651 | Curses.timeout = @delay * 1000 652 | ch = Curses.getch.chr rescue nil 653 | case ch 654 | when "\f" 655 | Curses.clear 656 | when "q", "Z", "z" 657 | break 658 | when 'i' 659 | @imode = (@imode == :both)? :soft : :both 660 | when 's' 661 | @imode = (@imode == :both)? :irq : :both 662 | when 't' 663 | @omode = (@omode == :top)? :table : :top 664 | when 'x' 665 | @omode = (@omode == :table)? :top : :table 666 | when 'e', 'p' 667 | @pps = !@pps 668 | when 'r' 669 | @reverse = !@reverse 670 | when 'c' 671 | @color = !@color 672 | when 'A' 673 | @ifilter = {} 674 | when 'a' 675 | @ifilter = {} 676 | @showall = !@showall 677 | when 'R' 678 | @showrps = !@showrps 679 | when '.' 680 | curses_enter("Pause, press enter to to continue: ", false) 681 | when 'd' 682 | d = curses_enter("Enter display interval: ") 683 | @delay = d.to_f if d.to_f > 0 684 | when 'h', '?' 685 | curses_output { show_help } 686 | Curses.timeout = -1 687 | ch = Curses.getch.chr rescue nil 688 | break if ch == 'q' 689 | end 690 | end 691 | 692 | -------------------------------------------------------------------------------- /libipt_NETFLOW.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only 2 | * 3 | * iptables helper for NETFLOW target 4 | * 5 | * 6 | * 7 | * This file is part of NetFlow exporting module. 8 | * 9 | * This program is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 2 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with this program. If not, see . 21 | * 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #define __EXPORTED_HEADERS__ 34 | #ifdef XTABLES 35 | #include 36 | #else 37 | #include 38 | #endif 39 | 40 | #ifdef XTABLES_VERSION_CODE // since 1.4.1 41 | #define MOD140 42 | #define iptables_target xtables_target 43 | #endif 44 | 45 | #ifdef iptables_target // only in 1.4.0 46 | #define MOD140 47 | #endif 48 | 49 | #ifdef MOD140 50 | #define ipt_entry_target xt_entry_target 51 | #define register_target xtables_register_target 52 | #define _IPT_ENTRY void 53 | #define _IPT_IP void 54 | #ifndef IPT_ALIGN 55 | #define IPT_ALIGN XT_ALIGN 56 | #endif 57 | #else // before 1.3.x 58 | #define _IPT_ENTRY struct ipt_entry 59 | #define _IPT_IP struct ipt_ip 60 | #endif 61 | 62 | #ifndef IPTABLES_VERSION 63 | #define IPTABLES_VERSION XTABLES_VERSION 64 | #endif 65 | 66 | static struct option opts[] = { 67 | { 0 } 68 | }; 69 | 70 | static void help(void) 71 | { 72 | printf("NETFLOW target\n"); 73 | } 74 | 75 | static int parse(int c, char **argv, int invert, unsigned int *flags, 76 | const _IPT_ENTRY *entry, 77 | struct ipt_entry_target **targetinfo) 78 | 79 | { 80 | return 1; 81 | } 82 | 83 | static void final_check(unsigned int flags) 84 | { 85 | } 86 | 87 | static void save(const _IPT_IP *ip, const struct ipt_entry_target *match) 88 | { 89 | } 90 | 91 | static void print(const _IPT_IP *ip, 92 | const struct ipt_entry_target *target, 93 | int numeric) 94 | { 95 | printf("NETFLOW "); 96 | } 97 | 98 | static struct iptables_target netflow = { 99 | .next = NULL, 100 | .name = "NETFLOW", 101 | .version = IPTABLES_VERSION, 102 | .size = IPT_ALIGN(0), 103 | .userspacesize = IPT_ALIGN(0), 104 | .help = &help, 105 | .parse = &parse, 106 | .final_check = &final_check, 107 | .print = &print, 108 | .save = &save, 109 | .extra_opts = opts 110 | }; 111 | 112 | #ifndef _init 113 | #define _init __attribute__((constructor)) _INIT 114 | #endif 115 | void _init(void) 116 | { 117 | register_target(&netflow); 118 | } 119 | -------------------------------------------------------------------------------- /murmur3.h: -------------------------------------------------------------------------------- 1 | /* MurmurHash3, based on https://code.google.com/p/smhasher of Austin Appleby. */ 2 | 3 | static __always_inline uint32_t rotl32(const uint32_t x, const int8_t r) 4 | { 5 | return (x << r) | (x >> (32 - r)); 6 | } 7 | 8 | static __always_inline uint32_t fmix32(register uint32_t h) 9 | { 10 | h ^= h >> 16; 11 | h *= 0x85ebca6b; 12 | h ^= h >> 13; 13 | h *= 0xc2b2ae35; 14 | h ^= h >> 16; 15 | return h; 16 | } 17 | 18 | static inline uint32_t murmur3(const void *key, const uint32_t len, const uint32_t seed) 19 | { 20 | const uint32_t c1 = 0xcc9e2d51; 21 | const uint32_t c2 = 0x1b873593; 22 | const uint32_t *blocks; 23 | const uint8_t *tail; 24 | register uint32_t h1 = seed; 25 | uint32_t k1 = 0; 26 | uint32_t i; 27 | 28 | blocks = (const uint32_t *)key; 29 | for (i = len / 4; i; --i) { 30 | h1 ^= rotl32(*blocks++ * c1, 15) * c2; 31 | h1 = rotl32(h1, 13) * 5 + 0xe6546b64; 32 | } 33 | tail = (const uint8_t*)blocks; 34 | switch (len & 3) { 35 | case 3: k1 ^= tail[2] << 16; fallthrough; 36 | case 2: k1 ^= tail[1] << 8; fallthrough; 37 | case 1: k1 ^= tail[0]; 38 | h1 ^= rotl32(k1 * c1, 15) * c2; 39 | } 40 | return fmix32(h1^ len); 41 | } 42 | 43 | -------------------------------------------------------------------------------- /openwrt/Makefile: -------------------------------------------------------------------------------- 1 | include $(TOPDIR)/rules.mk 2 | include $(INCLUDE_DIR)/kernel.mk 3 | 4 | PKG_NAME:=ipt-netflow 5 | PKG_RELEASE:=2 6 | 7 | PKG_SOURCE_URL:=https://github.com/aabc/$(PKG_NAME).git 8 | PKG_VERSION:=2.5.1 9 | PKG_SOURCE_VERSION:=v$(PKG_VERSION) 10 | 11 | #TO BUILD development version uncomment 2 rows below and remove patches 12 | #PKG_VERSION:=$(shell (git ls-remote $(PKG_SOURCE_URL) | grep refs/heads/master | cut -f 1 | head -c 7)) 13 | #PKG_SOURCE_VERSION:=HEAD 14 | 15 | PKG_SOURCE_PROTO:=git 16 | PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz 17 | 18 | PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) 19 | 20 | PKG_BUILD_DIR := $(KERNEL_BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION) 21 | PKG_DEPENDS:=iptables 22 | 23 | include $(INCLUDE_DIR)/package.mk 24 | 25 | 26 | define KernelPackage/ipt-netflow 27 | SECTION:=net 28 | CATEGORY:=Network 29 | SUBMENU:=Netflow 30 | TITLE:=Netflow iptables module for Linux kernel 31 | URL:=http://ipt-netflow.sourceforge.net/ 32 | FILES:=$(PKG_BUILD_DIR)/ipt_NETFLOW.ko 33 | DEPENDS:=+iptables +iptables-mod-netflow 34 | endef 35 | 36 | 37 | define Package/iptables-mod-netflow 38 | SECTION:=net 39 | CATEGORY:=Network 40 | SUBMENU:=Netflow 41 | TITLE:=Netflow iptables module for Linux kernel 42 | URL:=http://ipt-netflow.sourceforge.net/ 43 | #DEPENDS:=+kmod-ipt-netflow 44 | DEPENDS:=+iptables 45 | endef 46 | 47 | CONFIGURE_ARGS:= \ 48 | --kdir="$(LINUX_DIR)" 49 | 50 | define Package/iptables-mod-netflow/config 51 | menu "Configuration" 52 | depends on PACKAGE_iptables-mod-netflow 53 | config PACKAGE_iptables-mod-netflow_natevents 54 | bool "enables natevents support" 55 | default n 56 | config PACKAGE_iptables-mod-netflow_snmp-rules 57 | bool "enables SNMP-index conversion rules" 58 | default n 59 | config PACKAGE_iptables-mod-netflow_macaddress 60 | bool "enables MAC address for v9/IPFIX" 61 | default n 62 | config PACKAGE_iptables-mod-netflow_vlan 63 | bool "enables VLAN Ids for v9/IPFIX" 64 | default n 65 | config PACKAGE_iptables-mod-netflow_direction 66 | bool "enables flowDirection(61) Element" 67 | default n 68 | config PACKAGE_iptables-mod-netflow_sampler 69 | bool "enables Flow Sampling" 70 | default n 71 | config PACKAGE_iptables-mod-netflow_aggregation 72 | bool "enables aggregation rules" 73 | default n 74 | config PACKAGE_iptables-mod-netflow_promisc 75 | bool "enables promisc hack mode" 76 | default n 77 | config PACKAGE_iptables-mod-netflow_promisc-mpls 78 | bool "decapsulate MPLS in promisc mode" 79 | default n 80 | config PACKAGE_iptables-mod-netflow_physdev 81 | bool "enables physdev reporting" 82 | default n 83 | config PACKAGE_iptables-mod-netflow_physdev-override 84 | bool "to override interfaces" 85 | default n 86 | config PACKAGE_iptables-mod-netflow_snmp-agent 87 | bool "disables net-snmp agent" 88 | default y 89 | config PACKAGE_iptables-mod-netflow_dkms 90 | bool "disables DKMS support completely" 91 | default y 92 | config PACKAGE_iptables-mod-netflow_dkms-install 93 | bool "no DKMS install but still create dkms.conf" 94 | default n 95 | endmenu 96 | endef 97 | 98 | CONFIGURE_ARGS += \ 99 | $(if $(CONFIG_PACKAGE_iptables-mod-netflow_natevents),--enable-natevents) \ 100 | $(if $(CONFIG_PACKAGE_iptables-mod-netflow_snmp-rules),--enable-snmp-rules) \ 101 | $(if $(CONFIG_PACKAGE_iptables-mod-netflow_macaddress),--enable-macaddress) \ 102 | $(if $(CONFIG_PACKAGE_iptables-mod-netflow_vlan),--enable-vlan) \ 103 | $(if $(CONFIG_PACKAGE_iptables-mod-netflow_direction),--enable-direction) \ 104 | $(if $(CONFIG_PACKAGE_iptables-mod-netflow_sampler),--enable-sampler) \ 105 | $(if $(CONFIG_PACKAGE_iptables-mod-netflow_aggregation),--enable-aggregation) \ 106 | $(if $(CONFIG_PACKAGE_iptables-mod-netflow_promisc),--enable-promisc) \ 107 | $(if $(CONFIG_PACKAGE_iptables-mod-netflow_promisc-mpls),--promisc-mpls) \ 108 | $(if $(CONFIG_PACKAGE_iptables-mod-netflow_physdev),--enable-physdev) \ 109 | $(if $(CONFIG_PACKAGE_iptables-mod-netflow_physdev-override),--enable-physdev-override) \ 110 | $(if $(CONFIG_PACKAGE_iptables-mod-netflow_snmp-agent),--disable-snmp-agent) \ 111 | $(if $(CONFIG_PACKAGE_iptables-mod-netflow_dkms),--disable-dkms) \ 112 | $(if $(CONFIG_PACKAGE_iptables-mod-netflow_dkms-install),--disable-dkms-install) 113 | 114 | #TODO: --enable-sampler=hash --promisc-mpls=N 115 | 116 | 117 | $(eval $(call KernelPackage,ipt-netflow)) 118 | 119 | $(eval $(call Package,kmod-ipt-netflow)) 120 | 121 | define Package/iptables-mod-netflow/install 122 | $(MAKE) -C $(PKG_BUILD_DIR) DESTDIR=$(1) linstall 123 | #TODO: snmp install, dkms install 124 | endef 125 | 126 | $(eval $(call BuildPackage,iptables-mod-netflow)) 127 | -------------------------------------------------------------------------------- /openwrt/Readme.md: -------------------------------------------------------------------------------- 1 | Cross-compiling and packages for openwrt 2 | === 3 | 4 | Place Makefile in `packages/network/ipt-netflow` directory in OpenWRT bouldroot. 5 | Run `make menuconfig` and select package in Network/Netflow menu. Configure args partially supported. 6 | 7 | Run `make` to build full firmware or `make package/network/ipt-netflow/{clean,prepare,configure,compile,install}` to rebuild packages. 8 | 9 | To make git version uncomment two lines in Makefile. 10 | 11 | Tested to work on Chaos Calmer and Designated Driver with Atheros AR7xxx/AR9xxx target. 12 | 13 | For ipt-netflow 2.2 patches are needed, drop it for next version or git master to build. 14 | 15 | Making and installilng 16 | === 17 | 18 | ```shell 19 | mkdir debian-toolchain 20 | sudo debootstrap jessie debian-toolchain 21 | sudo chroot debian-toolchain 22 | 23 | . /etc/profile 24 | apt update 25 | apt install git ssh-client build-essential mercurial subversion \ 26 | binutils flex bzip2 asciidoc ncurses-dev libssl-dev gawk zlib1g-dev fastjar 27 | 28 | adduser user 29 | su user 30 | . /etc/profile 31 | cd ~ 32 | 33 | git clone https://github.com/openwrt/openwrt.git openwrt-trunk 34 | git clone https://github.com/aabc/ipt-netflow.git 35 | 36 | cd openwrt-trunk 37 | ./scripts/feeds update -a 38 | ln -s ~/ipt-netflow/openwrt/ package/network/ipt-netflow 39 | 40 | 41 | make menuconfig 42 | #select target and device 43 | #go to network/netflow and check both 44 | 45 | make 46 | #and go for dinner or a walk ;) 47 | #after five hours 48 | 49 | scp bin/ar71xx/packages/kernel/kmod-ipt-netflow_4.4.14+2.2-2_ar71xx.ipk \ 50 | root@192.168.236.79:/tmp/ 51 | scp bin/ar71xx/packages/base/iptables-mod-netflow_2.2-2_ar71xx.ipk \ 52 | root@192.168.236.79:/tmp/ 53 | scp bin/ar71xx/packages/base/kernel_4.4.14-1-abf9cc6feb410252d667326556dae184_ar71xx.ipk \ 54 | root@192.168.236.79:/tmp/ 55 | 56 | #goto router 57 | ssh root@192.168.236.79 58 | 59 | opkg install /tmp/*.ipk 60 | 61 | insmod /lib/modules/4.4.14/ipt_NETFLOW.ko 62 | sysctl -w net.netflow.protocol=5 63 | sysctl -w net.netflow.destination=192.168.236.34:2055 64 | 65 | iptables -I FORWARD -j NETFLOW 66 | iptables -I INPUT -j NETFLOW 67 | iptables -I OUTPUT -j NETFLOW 68 | 69 | ``` 70 | -------------------------------------------------------------------------------- /openwrt/patches/310-Makefile_crosscompile.patch: -------------------------------------------------------------------------------- 1 | Index: ipt-netflow-2.2/Makefile.in 2 | =================================================================== 3 | --- ipt-netflow-2.2.orig/Makefile.in 4 | +++ ipt-netflow-2.2/Makefile.in 5 | @@ -64,10 +64,10 @@ sinstall: | snmp_NETFLOW.so IPT-NETFLOW- 6 | fi 7 | 8 | %_sh.o: libipt_NETFLOW.c 9 | - gcc -O2 -Wall -Wunused $(IPTABLES_CFLAGS) -fPIC -o $@ -c libipt_NETFLOW.c 10 | + $(CC) $(CFLAGS) -O2 -Wall -Wunused $(IPTABLES_CFLAGS) -fPIC -o $@ -c libipt_NETFLOW.c 11 | 12 | %.so: %_sh.o 13 | - gcc -shared -o $@ $< 14 | + $(CC) -shared -o $@ $< 15 | 16 | version.h: ipt_NETFLOW.c ipt_NETFLOW.h compat.h Makefile 17 | @./version.sh --define > version.h 18 | -------------------------------------------------------------------------------- /raw_promisc.patch: -------------------------------------------------------------------------------- 1 | 2 | This simple hack will allow to see promisc traffic in raw table of 3 | iptables. Of course you will need to enable promisc on the interface. 4 | Refer to README.promisc for details. 5 | 6 | Example how to catch desired traffic: 7 | iptables -A PREROUTING -t raw -i eth2 -j NETFLOW 8 | 9 | 10 | --- linux-2.6.26/net/ipv4/ip_input.old.c 2008-07-14 01:51:29.000000000 +0400 11 | +++ linux-2.6.26/net/ipv4/ip_input.c 2008-08-06 14:02:16.000000000 +0400 12 | @@ -378,12 +378,6 @@ 13 | struct iphdr *iph; 14 | u32 len; 15 | 16 | - /* When the interface is in promisc. mode, drop all the crap 17 | - * that it receives, do not try to analyse it. 18 | - */ 19 | - if (skb->pkt_type == PACKET_OTHERHOST) 20 | - goto drop; 21 | - 22 | IP_INC_STATS_BH(IPSTATS_MIB_INRECEIVES); 23 | 24 | if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) { 25 | -------------------------------------------------------------------------------- /raw_promisc_debian_squeeze6.patch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aabc/ipt-netflow/d46ef265f2084eb92daa5d59f9a11df85c809357/raw_promisc_debian_squeeze6.patch -------------------------------------------------------------------------------- /snmp_NETFLOW.c: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only 2 | * 3 | * dlmod plugin for net-snmp for monitoring 4 | * ipt_NETFLOW module via IPT-NETFLOW-MIB. 5 | * 6 | * (c) 2014 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License version 2 as 10 | * published by the Free Software Foundation. 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #define iptNetflowMIB_oid 1, 3, 6, 1, 4, 1, 37476, 9000, 10, 1 /* .1.3.6.1.4.1.37476.9000.10.1 */ 24 | 25 | /* iptNetflowObjects */ 26 | static oid iptNetflowModule_oid[] = { iptNetflowMIB_oid, 1, 1 }; 27 | static oid iptNetflowSysctl_oid[] = { iptNetflowMIB_oid, 1, 2 }; 28 | /* iptNetflowStatistics */ 29 | static oid iptNetflowTotals_oid[] = { iptNetflowMIB_oid, 2, 1 }; 30 | static oid iptNetflowCpuTable_oid[] = { iptNetflowMIB_oid, 2, 2 }; 31 | static oid iptNetflowSockTable_oid[] = { iptNetflowMIB_oid, 2, 3 }; 32 | 33 | struct snmp_vars { 34 | int obj; 35 | int type; 36 | char *name; 37 | 38 | time_t ts; /* when value last read */ 39 | long long val64; 40 | }; 41 | 42 | struct snmp_vars modinfos[] = { 43 | {1, ASN_OCTET_STR, "name"}, 44 | {2, ASN_OCTET_STR, "version"}, 45 | {3, ASN_OCTET_STR, "srcversion"}, 46 | {4, ASN_OCTET_STR, "loadTime"}, /* DateAndTime */ 47 | {5, ASN_INTEGER, "refcnt"}, 48 | { 0 } 49 | }; 50 | #define MODINFO_NAME "ipt_NETFLOW" 51 | #define MODINFO_NAME_ID 1 52 | #define MODINFO_DATE_ID 4 53 | 54 | struct snmp_vars sysctls[] = { 55 | {1, ASN_INTEGER, "protocol"}, 56 | {2, ASN_INTEGER, "hashsize"}, 57 | {3, ASN_INTEGER, "maxflows"}, 58 | {4, ASN_INTEGER, "active_timeout"}, 59 | {5, ASN_INTEGER, "inactive_timeout"}, 60 | {6, ASN_INTEGER, "sndbuf"}, 61 | {7, ASN_OCTET_STR, "destination"}, 62 | {8, ASN_OCTET_STR, "aggregation"}, 63 | {9, ASN_OCTET_STR, "sampler"}, 64 | {10, ASN_INTEGER, "natevents"}, 65 | {11, ASN_INTEGER, "promisc"}, 66 | {12, ASN_OCTET_STR, "snmp-rules"}, 67 | {13, ASN_INTEGER, "scan-min"}, 68 | { 0 } 69 | }; 70 | 71 | struct snmp_vars totals[] = { 72 | {1, ASN_COUNTER64, "inBitRate"}, 73 | {2, ASN_GAUGE, "inPacketRate"}, 74 | {3, ASN_COUNTER64, "inFlows"}, 75 | {4, ASN_COUNTER64, "inPackets"}, 76 | {5, ASN_COUNTER64, "inBytes"}, 77 | {6, ASN_GAUGE, "hashMetric"}, 78 | {7, ASN_GAUGE, "hashMemory"}, 79 | {8, ASN_GAUGE, "hashFlows"}, 80 | {9, ASN_GAUGE, "hashPackets"}, 81 | {10, ASN_COUNTER64, "hashBytes"}, 82 | {11, ASN_COUNTER64, "dropPackets"}, 83 | {12, ASN_COUNTER64, "dropBytes"}, 84 | {13, ASN_GAUGE, "outByteRate"}, 85 | {14, ASN_COUNTER64, "outFlows"}, 86 | {15, ASN_COUNTER64, "outPackets"}, 87 | {16, ASN_COUNTER64, "outBytes"}, 88 | {17, ASN_COUNTER64, "lostFlows"}, 89 | {18, ASN_COUNTER64, "lostPackets"}, 90 | {19, ASN_COUNTER64, "lostBytes"}, 91 | {20, ASN_COUNTER, "errTotal"}, 92 | {21, ASN_COUNTER, "sndbufPeak"}, 93 | { 0 } 94 | }; 95 | #define TOTALS_METRIC_ID 6 96 | 97 | static netsnmp_table_data_set *cpu_data_set; 98 | static netsnmp_cache *stat_cache = NULL; 99 | 100 | struct snmp_vars cputable[] = { 101 | {1, ASN_INTEGER, "cpuIndex"}, 102 | {2, ASN_GAUGE, "cpuInPacketRate"}, 103 | {3, ASN_COUNTER64, "cpuInFlows"}, 104 | {4, ASN_COUNTER64, "cpuInPackets"}, 105 | {5, ASN_COUNTER64, "cpuInBytes"}, 106 | {6, ASN_GAUGE, "cpuHashMetric"}, 107 | {7, ASN_COUNTER64, "cpuDropPackets"}, 108 | {8, ASN_COUNTER64, "cpuDropBytes"}, 109 | {9, ASN_COUNTER, "cpuErrTrunc"}, 110 | {10, ASN_COUNTER, "cpuErrFrag"}, 111 | {11, ASN_COUNTER, "cpuErrAlloc"}, 112 | {12, ASN_COUNTER, "cpuErrMaxflows"}, 113 | { 0 } 114 | }; 115 | 116 | static netsnmp_table_data_set *sock_data_set; 117 | struct snmp_vars socktable[] = { 118 | {1, ASN_INTEGER, "sockIndex"}, 119 | {2, ASN_OCTET_STR, "sockDestination"}, 120 | {3, ASN_INTEGER, "sockActive"}, 121 | {4, ASN_COUNTER, "sockErrConnect"}, 122 | {5, ASN_COUNTER, "sockErrFull"}, 123 | {6, ASN_COUNTER, "sockErrCberr"}, 124 | {7, ASN_COUNTER, "sockErrOther"}, 125 | {8, ASN_GAUGE, "sockSndbuf"}, 126 | {9, ASN_GAUGE, "sockSndbufFill"}, 127 | {10, ASN_GAUGE, "sockSndbufPeak"}, 128 | { 0 } 129 | }; 130 | 131 | static time_t totals_ts; /* when statistics last read from kernel */ 132 | 133 | static int var_max(struct snmp_vars *head) 134 | { 135 | struct snmp_vars *sys; 136 | int max = 0; 137 | 138 | for (sys = head; sys->obj; sys++) 139 | if (max < sys->obj) 140 | max = sys->obj; 141 | return max; 142 | } 143 | 144 | static struct snmp_vars *find_varinfo(struct snmp_vars *head, const int obj) 145 | { 146 | struct snmp_vars *sys; 147 | 148 | for (sys = head; sys->obj; sys++) { 149 | if (sys->obj == obj) 150 | return sys; 151 | } 152 | return NULL; 153 | } 154 | 155 | static struct snmp_vars *find_varinfo_str(struct snmp_vars *head, const char *name) 156 | { 157 | struct snmp_vars *sys; 158 | 159 | for (sys = head; sys->obj; sys++) { 160 | if (!strcmp(sys->name, name)) 161 | return sys; 162 | } 163 | return NULL; 164 | } 165 | 166 | static void modinfo_fname(char *name, char *fname, size_t flen) 167 | { 168 | snprintf(fname, flen, "/sys/module/" MODINFO_NAME "/%s", name); 169 | } 170 | 171 | static void sysctl_fname(char *name, char *fname, size_t flen) 172 | { 173 | snprintf(fname, flen, "/proc/sys/net/netflow/%s", name); 174 | } 175 | 176 | static int sysctl_access_ok(char *name) 177 | { 178 | char fname[64]; 179 | 180 | sysctl_fname(name, fname, sizeof(fname)); 181 | if (access(fname, W_OK) < 0) 182 | return 0; 183 | return 1; 184 | } 185 | 186 | static char *file_read_string(char *name, char *buf, size_t size) 187 | { 188 | int fd = open(name, O_RDONLY); 189 | if (fd < 0) 190 | return NULL; 191 | int n = read(fd, buf, size - 1); 192 | if (n < 0) { 193 | close(fd); 194 | return NULL; 195 | } 196 | buf[n] = '\0'; 197 | close(fd); 198 | return buf; 199 | } 200 | 201 | static char *modinfo_read_string(char *name, char *buf, size_t size) 202 | { 203 | char fname[64]; 204 | 205 | modinfo_fname(name, fname, sizeof(fname)); 206 | return file_read_string(fname, buf, size); 207 | } 208 | 209 | static char *sysctl_read_string(char *name, char *buf, size_t size) 210 | { 211 | char fname[64]; 212 | 213 | sysctl_fname(name, fname, sizeof(fname)); 214 | return file_read_string(fname, buf, size); 215 | } 216 | 217 | static int sysctl_write_string(char *name, char *buf, size_t size) 218 | { 219 | char fname[64]; 220 | int fd; 221 | int n; 222 | 223 | sysctl_fname(name, fname, sizeof(fname)); 224 | fd = open(fname, O_RDWR, 0644); 225 | if (fd < 0) 226 | return fd; 227 | n = write(fd, buf, size); 228 | close(fd); 229 | return n; 230 | } 231 | 232 | static int sysctl_read(netsnmp_request_info *request, int obj) 233 | { 234 | struct snmp_vars *sys = find_varinfo(sysctls, obj); 235 | char buf[225]; 236 | char *p; 237 | long value; 238 | 239 | if (!sys) 240 | goto nosuchobject; 241 | 242 | p = sysctl_read_string(sys->name, buf, sizeof(buf)); 243 | if (!p) 244 | goto nosuchobject; 245 | 246 | switch (sys->type) { 247 | case ASN_INTEGER: 248 | value = atoi(p); 249 | snmp_set_var_typed_value(request->requestvb, 250 | sys->type, 251 | (u_char *)&value, sizeof(value)); 252 | return SNMP_ERR_NOERROR; 253 | case ASN_OCTET_STR: 254 | snmp_set_var_typed_value(request->requestvb, 255 | sys->type, 256 | (u_char *)p, strcspn(p, "\n")); 257 | return SNMP_ERR_NOERROR; 258 | } 259 | nosuchobject: 260 | netsnmp_request_set_error(request, SNMP_NOSUCHOBJECT); 261 | return SNMP_ERR_NOERROR; 262 | } 263 | 264 | static int sysctl_write(netsnmp_request_info *request, int obj) 265 | { 266 | struct snmp_vars *sys = find_varinfo(sysctls, obj); 267 | char buf[225]; 268 | int len; 269 | 270 | if (!sys) { 271 | netsnmp_request_set_error(request, SNMP_NOSUCHOBJECT); 272 | return SNMP_ERR_NOERROR; 273 | } 274 | switch (sys->type) { 275 | case ASN_INTEGER: 276 | snprintf(buf, sizeof(buf), "%ld\n", *(request->requestvb->val.integer)); 277 | break; 278 | case ASN_UNSIGNED: 279 | snprintf(buf, sizeof(buf), "%lu\n", *(request->requestvb->val.integer)); 280 | break; 281 | case ASN_OCTET_STR: 282 | snprintf(buf, sizeof(buf), "%s\n", request->requestvb->val.string); 283 | break; 284 | default: 285 | netsnmp_request_set_error(request, SNMP_ERR_WRONGTYPE); 286 | return SNMP_ERR_NOERROR; 287 | } 288 | len = strlen(buf); 289 | if (sysctl_write_string(sys->name, buf, len) < len) 290 | netsnmp_request_set_error(request, SNMP_ERR_BADVALUE); 291 | return SNMP_ERR_NOERROR; 292 | } 293 | 294 | static int iptNetflowModule_handler( 295 | netsnmp_mib_handler *handler, 296 | netsnmp_handler_registration *reginfo, 297 | netsnmp_agent_request_info *reqinfo, 298 | netsnmp_request_info *request) 299 | { 300 | struct snmp_vars *sys; 301 | oid obj; 302 | char buf[225]; 303 | char *p = NULL; 304 | long value; 305 | 306 | obj = request->requestvb->name[request->requestvb->name_length - 2]; 307 | sys = find_varinfo(modinfos, obj); 308 | if (!sys) { 309 | netsnmp_request_set_error(request, SNMP_ERR_NOSUCHNAME); 310 | return SNMP_ERR_NOERROR; 311 | } 312 | if (reqinfo->mode != MODE_GET) { 313 | netsnmp_request_set_error(request, SNMP_ERR_READONLY); 314 | return SNMP_ERR_NOERROR; 315 | } 316 | switch (obj) { 317 | case MODINFO_NAME_ID: 318 | p = MODINFO_NAME; 319 | break; 320 | case MODINFO_DATE_ID: { 321 | size_t len; 322 | struct stat st; 323 | 324 | modinfo_fname(".", buf, sizeof(buf)); 325 | if (stat(buf, &st) < 0) 326 | break; 327 | p = (char *)date_n_time(&st.st_mtime, &len); 328 | snmp_set_var_typed_value(request->requestvb, ASN_OCTET_STR, p, len); 329 | return SNMP_ERR_NOERROR; 330 | } 331 | default: 332 | p = modinfo_read_string(sys->name, buf, sizeof(buf)); 333 | } 334 | if (!p) { 335 | netsnmp_request_set_error(request, SNMP_ERR_NOSUCHNAME); 336 | return SNMP_ERR_NOERROR; 337 | } 338 | 339 | switch (sys->type) { 340 | case ASN_INTEGER: 341 | value = atoi(p); 342 | snmp_set_var_typed_value(request->requestvb, 343 | sys->type, 344 | (u_char *)&value, sizeof(value)); 345 | break; 346 | case ASN_OCTET_STR: 347 | snmp_set_var_typed_value(request->requestvb, 348 | sys->type, 349 | (u_char *)p, strcspn(p, "\n")); 350 | break; 351 | default: 352 | netsnmp_request_set_error(request, SNMP_ERR_WRONGTYPE); 353 | 354 | } 355 | return SNMP_ERR_NOERROR; 356 | } 357 | 358 | static int iptNetflowSysctl_handler( 359 | netsnmp_mib_handler *handler, 360 | netsnmp_handler_registration *reginfo, 361 | netsnmp_agent_request_info *reqinfo, 362 | netsnmp_request_info *request) 363 | { 364 | struct snmp_vars *sys; 365 | oid obj; 366 | 367 | obj = request->requestvb->name[request->requestvb->name_length - 2]; 368 | switch (reqinfo->mode) { 369 | case MODE_GET: 370 | return sysctl_read(request, obj); 371 | case MODE_SET_RESERVE1: 372 | sys = find_varinfo(sysctls, obj); 373 | if (!sys || !sysctl_access_ok(sys->name)) 374 | netsnmp_request_set_error(request, SNMP_ERR_NOSUCHNAME); 375 | if (sys && request->requestvb->type != sys->type) 376 | netsnmp_request_set_error(request, SNMP_ERR_WRONGTYPE); 377 | break; 378 | case MODE_SET_RESERVE2: 379 | case MODE_SET_FREE: 380 | case MODE_SET_UNDO: 381 | case MODE_SET_COMMIT: 382 | return SNMP_ERR_NOERROR; 383 | case MODE_SET_ACTION: 384 | return sysctl_write(request, obj); 385 | default: 386 | return SNMP_ERR_GENERR; 387 | 388 | } 389 | return SNMP_ERR_NOERROR; 390 | } 391 | 392 | #define TOTAL_INTERVAL 1 393 | 394 | static void clear_data_set(netsnmp_table_data_set *data_set) 395 | { 396 | netsnmp_table_row *row, *nextrow; 397 | 398 | for (row = netsnmp_table_data_set_get_first_row(data_set); row; row = nextrow) { 399 | nextrow = netsnmp_table_data_set_get_next_row(data_set, row); 400 | netsnmp_table_dataset_remove_and_delete_row(data_set, row); 401 | } 402 | } 403 | 404 | static void parse_table_row( 405 | int cpu, 406 | char *p, 407 | struct snmp_vars *sys, 408 | netsnmp_table_data_set *data_set) 409 | { 410 | netsnmp_table_row *row; 411 | 412 | row = netsnmp_create_table_data_row(); 413 | netsnmp_table_row_add_index(row, ASN_INTEGER, (u_char *)&cpu, sizeof(cpu)); 414 | 415 | if (sys == cputable) { 416 | /* add cpuIndex as column too to break SMIv2 */ 417 | netsnmp_set_row_column(row, 1, sys->type, (char *)&cpu, sizeof(cpu)); 418 | } 419 | for (++sys; p && sys->obj; sys++) { 420 | char *val; 421 | long long val64; 422 | unsigned int uval32; 423 | int val32; 424 | struct counter64 c64; 425 | 426 | p += strspn(p, " \t"); 427 | val = p; 428 | if ((p = strpbrk(p, " \t"))) 429 | *p++ = '\0'; 430 | if (index(val, '.')) { 431 | double d = strtod(val, NULL); 432 | 433 | val64 = (long long)(d * 100); 434 | } else 435 | val64 = strtoll(val, NULL, 10); 436 | 437 | switch (sys->type) { 438 | case ASN_OCTET_STR: 439 | netsnmp_set_row_column(row, sys->obj, 440 | sys->type, (char *)val, strlen(val)); 441 | break; 442 | case ASN_INTEGER: 443 | case ASN_GAUGE: 444 | val32 = (int)val64; 445 | netsnmp_set_row_column(row, sys->obj, 446 | sys->type, (char *)&val32, sizeof(val32)); 447 | break; 448 | case ASN_COUNTER: 449 | uval32 = (unsigned int)val64; 450 | netsnmp_set_row_column(row, sys->obj, 451 | sys->type, (char *)&uval32, sizeof(uval32)); 452 | break; 453 | case ASN_COUNTER64: 454 | c64.low = (uint32_t)val64; 455 | c64.high = val64 >> 32; 456 | netsnmp_set_row_column(row, sys->obj, 457 | sys->type, (char *)&c64, sizeof(c64)); 458 | break; 459 | default: 460 | netsnmp_table_dataset_delete_row(row); 461 | continue; 462 | } 463 | 464 | } 465 | netsnmp_table_data_add_row(data_set->table, row); 466 | } 467 | 468 | static void grab_ipt_netflow_snmp(time_t now) 469 | { 470 | static char buf[4096]; 471 | int fd; 472 | int n; 473 | char *p = buf; 474 | 475 | if ((now - totals_ts) < (TOTAL_INTERVAL + 1)) 476 | return; 477 | 478 | if ((fd = open("/proc/net/stat/ipt_netflow_snmp", O_RDONLY)) < 0) 479 | return; 480 | 481 | n = read(fd, buf, sizeof(buf) - 1); 482 | close(fd); 483 | if (n <= 0) 484 | return; 485 | buf[n] = '\0'; 486 | 487 | DEBUGMSGTL(("netflow", "%s\n", buf)); 488 | clear_data_set(cpu_data_set); 489 | clear_data_set(sock_data_set); 490 | while (*p) { 491 | struct snmp_vars *sys; 492 | char *name = p; 493 | char *val; 494 | 495 | if (!(p = strpbrk(p, " \t"))) 496 | break; 497 | *p++ = '\0'; 498 | val = p + strspn(p, " \t"); 499 | p = index(p, '\n'); 500 | *p++ = '\0'; 501 | 502 | if (!strncmp(name, "cpu", 3)) { 503 | parse_table_row(atoi(name + 3), val, cputable, cpu_data_set); 504 | continue; 505 | } else if (!strncmp(name, "sock", 4)) { 506 | parse_table_row(atoi(name + 4), val, socktable, sock_data_set); 507 | continue; 508 | } 509 | if (!(sys = find_varinfo_str(totals, name))) 510 | continue; 511 | if (index(val, '.')) { 512 | double d = strtod(val, NULL); 513 | sys->val64 = (long long)(d * 100); 514 | } else 515 | sys->val64 = strtoll(val, NULL, 10); 516 | sys->ts = now; 517 | } 518 | totals_ts = now; 519 | } 520 | 521 | static int iptNetflowTotals_handler( 522 | netsnmp_mib_handler *handler, 523 | netsnmp_handler_registration *reginfo, 524 | netsnmp_agent_request_info *reqinfo, 525 | netsnmp_request_info *request) 526 | { 527 | struct snmp_vars *sys; 528 | time_t now = time(NULL); 529 | oid obj; 530 | unsigned int uval32; 531 | int val32; 532 | struct counter64 c64; 533 | 534 | grab_ipt_netflow_snmp(now); 535 | 536 | obj = request->requestvb->name[request->requestvb->name_length - 2]; 537 | sys = find_varinfo(totals, obj); 538 | if (!sys || ((now - sys->ts) > (TOTAL_INTERVAL * 2 + 3))) { 539 | netsnmp_request_set_error(request, SNMP_ERR_NOSUCHNAME); 540 | return SNMP_ERR_NOERROR; 541 | } 542 | if (reqinfo->mode != MODE_GET) { 543 | netsnmp_request_set_error(request, SNMP_ERR_READONLY); 544 | return SNMP_ERR_NOERROR; 545 | } 546 | switch (sys->type) { 547 | case ASN_GAUGE: 548 | val32 = (int)sys->val64; 549 | snmp_set_var_typed_value(request->requestvb, 550 | sys->type, (u_char *)&val32, sizeof(val32)); 551 | break; 552 | case ASN_COUNTER: 553 | uval32 = (unsigned int)sys->val64; 554 | snmp_set_var_typed_value(request->requestvb, 555 | sys->type, (u_char *)&uval32, sizeof(uval32)); 556 | break; 557 | case ASN_COUNTER64: 558 | c64.low = (uint32_t)sys->val64; 559 | c64.high = sys->val64 >> 32; 560 | snmp_set_var_typed_value(request->requestvb, 561 | ASN_COUNTER64, (u_char *)&c64, sizeof(c64)); 562 | break; 563 | default: 564 | return SNMP_ERR_GENERR; 565 | } 566 | return SNMP_ERR_NOERROR; 567 | } 568 | 569 | static int stat_cache_load(netsnmp_cache *cache, void *x) 570 | { 571 | grab_ipt_netflow_snmp(time(NULL)); 572 | return 0; 573 | } 574 | 575 | static void dummy_cache_free(netsnmp_cache *cache, void *x) 576 | { 577 | /* free_cache callback is not always checked for NULL 578 | * pointer. */ 579 | } 580 | 581 | void init_netflow(void) 582 | { 583 | netsnmp_handler_registration *reg; 584 | struct snmp_vars *sys; 585 | 586 | /* snmpd -f -L -Dnetflow,dlmod */ 587 | DEBUGMSGTL(("netflow", "init_netflow\n")); 588 | 589 | netsnmp_register_scalar_group( 590 | netsnmp_create_handler_registration( 591 | "iptNetflowModule", 592 | iptNetflowModule_handler, 593 | iptNetflowModule_oid, 594 | OID_LENGTH(iptNetflowModule_oid), 595 | HANDLER_CAN_RONLY), 596 | 1, var_max(modinfos)); 597 | 598 | netsnmp_register_scalar_group( 599 | netsnmp_create_handler_registration( 600 | "iptNetflowSysctl", 601 | iptNetflowSysctl_handler, 602 | iptNetflowSysctl_oid, 603 | OID_LENGTH(iptNetflowSysctl_oid), 604 | HANDLER_CAN_RWRITE), 605 | 1, var_max(sysctls)); 606 | 607 | netsnmp_register_scalar_group( 608 | netsnmp_create_handler_registration( 609 | "iptNetflowTotals", 610 | iptNetflowTotals_handler, 611 | iptNetflowTotals_oid, 612 | OID_LENGTH(iptNetflowTotals_oid), 613 | HANDLER_CAN_RONLY), 614 | 1, var_max(totals)); 615 | 616 | /* Register first table. */ 617 | reg = netsnmp_create_handler_registration( 618 | "iptNetflowCpuTable", /* no handler */ NULL, 619 | iptNetflowCpuTable_oid, OID_LENGTH(iptNetflowCpuTable_oid), 620 | HANDLER_CAN_RONLY); 621 | 622 | /* set up columns */ 623 | cpu_data_set = netsnmp_create_table_data_set("iptNetflowCpuDataSet"); 624 | netsnmp_table_set_add_indexes(cpu_data_set, ASN_INTEGER, 0); 625 | /* I include cpuIndex into columns, which is not SMIv2'ish */ 626 | for (sys = cputable; sys->obj; sys++) 627 | netsnmp_table_set_add_default_row(cpu_data_set, sys->obj, sys->type, 0, NULL, 0); 628 | netsnmp_register_table_data_set(reg, cpu_data_set, NULL); 629 | 630 | /* cache handler will load actual data, and it needs to be 631 | * injected in front of dataset handler to be called first */ 632 | stat_cache = netsnmp_cache_create( 633 | /* no timeout */ -1, 634 | stat_cache_load, dummy_cache_free, 635 | iptNetflowCpuTable_oid, OID_LENGTH(iptNetflowCpuTable_oid)); 636 | netsnmp_inject_handler(reg, netsnmp_cache_handler_get(stat_cache)); 637 | 638 | /* Register second table. */ 639 | reg = netsnmp_create_handler_registration( 640 | "iptNetflowSockTable", /* no handler */ NULL, 641 | iptNetflowSockTable_oid, OID_LENGTH(iptNetflowSockTable_oid), 642 | HANDLER_CAN_RONLY); 643 | 644 | /* set up columns */ 645 | sock_data_set = netsnmp_create_table_data_set("iptNetflowSockDataSet"); 646 | /* I don't include sockIndex into columns, which is more SMIv2'ish */ 647 | netsnmp_table_set_add_indexes(sock_data_set, ASN_INTEGER, 0); 648 | for (sys = &socktable[1]; sys->obj; sys++) 649 | netsnmp_table_set_add_default_row(sock_data_set, sys->obj, sys->type, 0, NULL, 0); 650 | netsnmp_register_table_data_set(reg, sock_data_set, NULL); 651 | 652 | /* as before, cache handler will load actual data, and it needs 653 | * to be injected in front of dataset handler to be called first */ 654 | stat_cache = netsnmp_cache_create( 655 | /* no timeout */ -1, 656 | stat_cache_load, dummy_cache_free, 657 | iptNetflowSockTable_oid, OID_LENGTH(iptNetflowSockTable_oid)); 658 | netsnmp_inject_handler(reg, netsnmp_cache_handler_get(stat_cache)); 659 | } 660 | 661 | void deinit_netflow(void) 662 | { 663 | DEBUGMSGTL(("netflow", "deinit_netflow\n")); 664 | } 665 | 666 | -------------------------------------------------------------------------------- /test_update_config.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -efu 2 | # SPDX-License-Identifier: GPL-2.0-only 3 | # 4 | # Update default .config for values required to run tests 5 | # 6 | 7 | COLOR=11 8 | V() { 9 | [ -t 1 ] && tput setaf "$COLOR" 10 | printf '+' 11 | printf ' %q' "$@" 12 | printf '\n' 13 | [ -t 1 ] && tput op 14 | "$@" 15 | } 16 | 17 | for opt; do 18 | case $opt in 19 | --kdir=*) KDIR=${opt#*=} ;; 20 | --checkout=*) BRANCH=${opt#*=} ;& 21 | --defconfig) DEFCONFIG=defconfig ;; 22 | --debug) ADD_DEBUG=y ;; 23 | --force) FORCE=--force ;; 24 | --prepare) TARGETS="prepare modules_prepare" ;& 25 | --clean) CLEAN=clean ;; 26 | --cmd=*) KBUILD_PREPARE_CMD=${opt#*=} ;; 27 | --build) DO_BUILD=y ;; 28 | --configure) DO_CONFIGURE=y ;; 29 | --pick=*) PICKS+=("${opt#*=}") ;; 30 | --*) echo >&2 "$0: Unknown option $opt"; exit 1 ;; 31 | gcc-*) OPTS+=(CC=$opt HOSTCC=$opt) ;; 32 | -no-* | -[fDWO]*) KBUILD_CFLAGS+=("$opt") ;; 33 | *=*) OPTS+=("${opt%%=*}=${opt#*=}") ;; 34 | *) echo >&2 "$0: Unknown argument $opt"; exit 1 ;; 35 | esac 36 | done 37 | 38 | # Patch applying command assuming --force checkout. 39 | [ -n "$KBUILD_PREPARE_CMD" ] && [ -n "$TARGETS" ] && FORCE=-f 40 | 41 | [ -n "${KDIR-}" ] && V cd "$KDIR" 42 | [ -n "${BRANCH-}" ] && V git switch ${FORCE-} --detach "$BRANCH" 43 | [ -n "${DEFCONFIG-}" ] && V make $DEFCONFIG 44 | 45 | V cp -f .config .config-pkt-netflow.bak 46 | 47 | if type virtme-configkernel >/dev/null 2>&1; then 48 | V virtme-configkernel --update 49 | fi 50 | 51 | V scripts/config \ 52 | -e CONFIG_VETH \ 53 | -e CONFIG_PACKET \ 54 | -e CONFIG_NETFILTER \ 55 | -e CONFIG_NETFILTER_XTABLES \ 56 | -e NETFILTER_ADVANCED \ 57 | -e CONFIG_IP_NF_FILTER \ 58 | -e CONFIG_IP_NF_IPTABLES \ 59 | -e CONFIG_IP6_NF_FILTER \ 60 | -e CONFIG_NF_CONNTRACK_EVENTS \ 61 | -e CONFIG_VLAN_8021Q \ 62 | 63 | if [ -n "${ADD_DEBUG-}" ]; then 64 | V scripts/config \ 65 | -e CONFIG_LOCK_DEBUGGING_SUPPORT \ 66 | -e CONFIG_PROVE_LOCKING \ 67 | -e CONFIG_DEBUG_SPINLOCK \ 68 | -e CONFIG_FRAME_POINTER \ 69 | -d CONFIG_RANDOMIZE_BASE \ 70 | 71 | fi 72 | 73 | V make olddefconfig 74 | 75 | V scripts/diffconfig .config-pkt-netflow.bak .config || : 76 | 77 | [ -n "${CLEAN-}" ] && V make $CLEAN 78 | [ -n "${KBUILD_PREPARE_CMD-}" ] && V eval "$KBUILD_PREPARE_CMD" || : 79 | for commit in "${PICKS[@]}"; do 80 | V git cherry-pick --no-commit "$commit" || : 81 | done 82 | [ -n "${KBUILD_CFLAGS-}" ] && OPTS+=("KBUILD_CFLAGS=${KBUILD_CFLAGS[*]}") 83 | [ -n "${TARGETS-}" ] && V make $TARGETS "${OPTS[@]}" 84 | 85 | echo 86 | V cd "$OLDPWD" 87 | COLOR=14 88 | 89 | if [ -n "${DO_CONFIGURE-}" ]; then 90 | readarray -t confs <<-EOF 91 | --disable-snmp-agent 92 | --enable-aggregation 93 | --enable-natevents 94 | --enable-snmp-rules 95 | --enable-macaddress 96 | --enable-vlan 97 | --promisc-mpls 98 | --enable-direction 99 | --enable-sampler 100 | --enable-sampler=hash 101 | --enable-promisc --promisc-mpls 102 | --enable-physdev 103 | --enable-physdev-override 104 | EOF 105 | mv -f Makefile Makefile- || : 106 | V ./configure ${confs[@]} 107 | fi 108 | 109 | if [ -n "${DO_BUILD-}" ]; then 110 | V make "${OPTS[@]}" $CLEAN ipt_NETFLOW.ko 111 | size ipt_NETFLOW.ko 112 | fi 113 | 114 | # export XTABLES_LIBDIR= 115 | -------------------------------------------------------------------------------- /testing.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | if [ "$1" = "" ]; then 6 | echo Maintainer only tool. 7 | exit 1 8 | elif [ "$1" = all ]; then 9 | exec bash $0 linux-2.6.18 centos5 linux-3.11.2 centos6 linux-3.4.66 linux-3.9.11 centos7 linux-3.14 linux-3.17 linux-3.19 10 | exit 1 11 | fi 12 | 13 | smilint IPT-NETFLOW-MIB.my 14 | 15 | cfg=() 16 | echo -n Testing for: 17 | for k in "$@"; do 18 | if [ ! -d /usr/src/$k ]; then continue; fi 19 | echo -n " $k" 20 | cfg+=("./configure --kdir=/usr/src/$k") 21 | done 22 | echo 23 | 24 | readarray -t opts </dev/null 2>&1; then \ 16 | GVERSION=`git describe --dirty 2>/dev/null` 17 | if [ "$GVERSION" ]; then 18 | MVERSION=${GVERSION#v} 19 | fi 20 | else 21 | GVERSION= 22 | fi 23 | 24 | if [ "$1" = --define ]; then 25 | # called from Makefile to create version.h 26 | # which should contain GITVERSION or be empty. 27 | if [ "$GVERSION" ]; then 28 | echo "#define GITVERSION \"$MVERSION\"" 29 | else 30 | echo "/* placeholder, because kernel doesn't like empty files */" 31 | fi 32 | else 33 | # normal run 34 | echo $MVERSION 35 | fi 36 | --------------------------------------------------------------------------------