├── LICENSE ├── Makefile ├── README.md ├── compat.h ├── libxt_NAT.c ├── xt_NAT.c └── xt_NAT.h /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | KVER ?= $(shell uname -r) 2 | KDIR ?= /lib/modules/$(KVER)/build/ 3 | DEPMOD = /sbin/depmod -a 4 | CC ?= gcc 5 | obj-m = xt_NAT.o 6 | CFLAGS_xt_NAT.o := -DDEBUG 7 | 8 | all: xt_NAT.ko libxt_NAT.so 9 | 10 | xt_NAT.ko: xt_NAT.c 11 | make -C $(KDIR) M=$(CURDIR) modules CONFIG_DEBUG_INFO=y 12 | -sync 13 | 14 | %_sh.o: libxt_NAT.c 15 | gcc -O2 -Wall -Wunused -fPIC -o $@ -c $< 16 | 17 | %.so: %_sh.o 18 | gcc -shared -o $@ $< 19 | 20 | sparse: clean | xt_NAT.c xt_NAT.h 21 | make -C $(KDIR) M=$(CURDIR) modules C=1 22 | 23 | cppcheck: 24 | cppcheck -I $(KDIR)/include --enable=all --inconclusive xt_NAT.c 25 | cppcheck libxt_NAT.c 26 | 27 | coverity: 28 | coverity-submit -v 29 | 30 | clean: 31 | make -C $(KDIR) M=$(CURDIR) clean 32 | -rm -f *.so *_sh.o *.o modules.order 33 | 34 | install: | minstall linstall 35 | 36 | minstall: | xt_NAT.ko 37 | make -C $(KDIR) M=$(CURDIR) modules_install INSTALL_MOD_PATH=$(DESTDIR) 38 | 39 | linstall: libxt_NAT.so 40 | install -D $< $(DESTDIR)$(shell pkg-config --variable xtlibdir xtables)/$< 41 | 42 | uninstall: 43 | -rm -f $(DESTDIR)$(shell pkg-config --variable xtlibdir xtables)/libxt_NAT.so 44 | -rm -f $(KDIR)/extra/xt_NAT.ko 45 | 46 | load: all 47 | -sync 48 | -modprobe x_tables 49 | -mkdir -p /lib64/modules/`uname -r`/kernel/net/ipv4/ 50 | -cp xt_NAT.ko /lib64/modules/`uname -r`/kernel/net/ipv4/ 51 | -depmod `uname -r` 52 | -modprobe xt_NAT 53 | -iptables-restore < iptables.rules 54 | -conntrack -F 55 | unload: 56 | -/etc/init.d/iptables restart 57 | -rmmod xt_NAT.ko 58 | del: 59 | -sync 60 | reload: unload clean load 61 | 62 | .PHONY: all minstall linstall install uninstall clean cppcheck 63 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # xt_NAT 2 | ## Description 3 | This Full Cone NAT xtables module was developed as a replace for the conntrack NAT to provide Assymetric NAT features on Linux systems that can be used as a Carrier Grade NAT in small ISP networks. 4 | 5 | It allows to have 40Gbps NAT on commodity servers like 2*Xeon E5-2698 v3 @ 2.30GHz (2 x 16 Cores) with Intel X710/XL710/X540 10G adapters. 6 | 7 | Compatibility tested with Linux Kernel 3.18 and 4.1 8 | ## Features 9 | * PAT/NAPT work mode - translates many users into a single NAT IP 10 | * Assymetric (Full Cone) NAT - allows inbound connections from any source IP address and any source port, as long as the NAT rule exists 11 | * Support of TCP/UDP/ICMP/Generic IP protocols 12 | * IP Pooling Paired mode - the same NAT IP is used for all sessions of a subscriber 13 | * Endpoint Independent Mapping - the same NAT_IP:NAT_Port mapping is used for traffic sent from same subscriber IP 14 | address and port to any external IP address and port 15 | * Hairpinning - allows communication between two internal subscribers or internal hosts using the NAT IP 16 | * User quotas support. Default value is 1000 max connections for each user (for each protocol independly) 17 | * No ALGs for FTP/SIP/PPTP are implemented 18 | * NAT events export using Netflow v5 19 | * NAT statistics via /proc interface 20 | 21 | ## Installation 22 | ``` 23 | $ make 24 | $ sudo make install 25 | $ sudo depmod -a 26 | ``` 27 | 28 | ## Usage 29 | ### NAT functionality 30 | * Define NAT Pool for the xt_NAT module: 31 | ``` 32 | $ sudo modprobe xt_NAT nat_pool=- 33 | ``` 34 | * Disable conntrack for the traffic that handled by the xt_NAT module: 35 | ``` 36 | $ sudo iptables -t raw -A PREROUTING -s -j CT --notrack 37 | $ sudo iptables -t raw -A PREROUTING -d -j CT --notrack 38 | ``` 39 | * Add iptables rule to use xt_NAT module for User's traffic (from Internet to Users): 40 | ``` 41 | $ sudo iptables -t raw -A PREROUTING -d -j NAT --dnat 42 | $ sudo iptables -A FORWARD -d -i -o -j ACCEPT 43 | ``` 44 | * Add iptables rule to use xt_NAT module for User's traffic (from Internet to Users): 45 | ``` 46 | $ sudo iptables -A FORWARD -s -i -o -j NAT –snat 47 | ``` 48 | ### NAT Events Export 49 | Just add ``nf_dest`` option with a list of the Netflow v5 collectors to the xt_NAT module parameters: 50 | ``` 51 | $ sudo modprobe xt_NAT nat_pool=- nf_dest=127.0.0.1:2055 52 | ``` 53 | ## NAT Statistics 54 | NAT statistics are available via the ```/proc/net/NAT/*``` directory: 55 | * /proc/net/NAT/sessions - NAT sessions for all users 56 | * /proc/net/NAT/users - NAT users with their NAT IPs 57 | * /proc/net/NAT/statistics - internal counters 58 | -------------------------------------------------------------------------------- /compat.h: -------------------------------------------------------------------------------- 1 | /* This code is derived from the Linux Kernel sources intended 2 | * to maintain compatibility with different Kernel versions. 3 | * Copyright of original source is of respective Linux Kernel authors. 4 | * License is GPLv2. 5 | */ 6 | 7 | #ifndef COMPAT_NAT_H 8 | #define COMPAT_NAT_H 9 | 10 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,2,0) 11 | # define sock_create_kern(f, t, p, s) sock_create_kern(&init_net, f, t, p, s) 12 | #endif 13 | 14 | #endif /* COMPAT_NAT_H */ 15 | 16 | -------------------------------------------------------------------------------- /libxt_NAT.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include "xt_NAT.h" 8 | 9 | enum { 10 | F_SNAT = 1 << 0, 11 | F_DNAT = 1 << 1, 12 | }; 13 | 14 | static const struct option nat_tg_opts[] = { 15 | {.name = "snat", .has_arg = false, .val = 's'}, 16 | {.name = "dnat", .has_arg = false, .val = 'd'}, 17 | {NULL}, 18 | }; 19 | 20 | static void nat_tg_help(void) 21 | { 22 | printf( 23 | "NAT target options:\n" 24 | " --snat Create NAT translation from Inside to Outside\n" 25 | " --dnat Allow NAT for revert traffic from Outside to Inside\n"); 26 | } 27 | 28 | static int nat_tg_parse(int c, char **argv, int invert, unsigned int *flags, 29 | const void *entry, struct xt_entry_target **target) 30 | { 31 | struct xt_nat_tginfo *info = (void *)(*target)->data; 32 | 33 | switch (c) { 34 | case 's': 35 | info->variant = XTNAT_SNAT; 36 | *flags |= F_SNAT; 37 | return true; 38 | case 'd': 39 | info->variant = XTNAT_DNAT; 40 | *flags |= F_DNAT; 41 | return true; 42 | } 43 | return false; 44 | } 45 | 46 | static void nat_tg_check(unsigned int flags) 47 | { 48 | if (flags == (F_SNAT | F_DNAT)) 49 | xtables_error(PARAMETER_PROBLEM, 50 | "NAT: only one action can be used at a time"); 51 | } 52 | 53 | static void nat_tg_save(const void *ip, 54 | const struct xt_entry_target *target) 55 | { 56 | const struct xt_nat_tginfo *info = (const void *)target->data; 57 | 58 | switch (info->variant) { 59 | case XTNAT_SNAT: 60 | printf(" --snat "); 61 | break; 62 | case XTNAT_DNAT: 63 | printf(" --dnat "); 64 | break; 65 | } 66 | } 67 | 68 | static void nat_tg_print(const void *ip, 69 | const struct xt_entry_target *target, int numeric) 70 | { 71 | printf(" -j NAT"); 72 | nat_tg_save(ip, target); 73 | } 74 | 75 | static struct xtables_target nat_tg_reg = { 76 | .version = XTABLES_VERSION, 77 | .name = "NAT", 78 | .family = NFPROTO_IPV4, 79 | .size = XT_ALIGN(sizeof(struct xt_nat_tginfo)), 80 | .userspacesize = XT_ALIGN(sizeof(struct xt_nat_tginfo)), 81 | .help = nat_tg_help, 82 | .parse = nat_tg_parse, 83 | .final_check = nat_tg_check, 84 | .print = nat_tg_print, 85 | .save = nat_tg_save, 86 | .extra_opts = nat_tg_opts, 87 | }; 88 | 89 | static __attribute__((constructor)) void nat_tg_ldr(void) 90 | { 91 | xtables_register_target(&nat_tg_reg); 92 | } 93 | 94 | -------------------------------------------------------------------------------- /xt_NAT.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "compat.h" 17 | #include "xt_NAT.h" 18 | 19 | #define FLAG_REPLIED (1 << 0) /* 000001 */ 20 | #define FLAG_TCP_FIN (1 << 1) /* 000010 */ 21 | 22 | #define TCP_SYN_ACK 0x12 23 | #define TCP_FIN_RST 0x05 24 | 25 | static LIST_HEAD(usock_list); 26 | static int sndbuf = 1310720; 27 | static int engine_id = 0; 28 | static unsigned int pdu_data_records = 0; 29 | static unsigned int pdu_seq = 0; 30 | struct netflow5_pdu pdu; 31 | 32 | static DEFINE_SPINLOCK(nfsend_lock); 33 | 34 | static atomic64_t sessions_active = ATOMIC_INIT(0); 35 | static atomic64_t users_active = ATOMIC_INIT(0); 36 | static atomic64_t sessions_tried = ATOMIC_INIT(0); 37 | static atomic64_t sessions_created = ATOMIC_INIT(0); 38 | static atomic64_t dnat_dropped = ATOMIC_INIT(0); 39 | static atomic64_t frags = ATOMIC_INIT(0); 40 | static atomic64_t related_icmp = ATOMIC_INIT(0); 41 | 42 | static char nat_pool_buf[128] = "127.0.0.1-127.0.0.1"; 43 | static char *nat_pool = nat_pool_buf; 44 | module_param(nat_pool, charp, 0444); 45 | MODULE_PARM_DESC(nat_pool, "NAT pool range (addr_start-addr_end), default = 127.0.0.1-127.0.0.1"); 46 | 47 | static int nat_hash_size = 256 * 1024; 48 | module_param(nat_hash_size, int, 0444); 49 | MODULE_PARM_DESC(nat_hash_size, "nat hash size, default = 256k"); 50 | 51 | static int users_hash_size = 4096; 52 | module_param(users_hash_size, int, 0444); 53 | MODULE_PARM_DESC(users_hash_size, "users hash size, default = 4k"); 54 | 55 | static char nf_dest_buf[128] = ""; 56 | static char *nf_dest = nf_dest_buf; 57 | module_param(nf_dest, charp, 0444); 58 | MODULE_PARM_DESC(nf_dest, "Netflow v5 collectors (addr1:port1[,addr2:port2]), default = none"); 59 | 60 | u_int32_t nat_htable_vector = 0; 61 | u_int32_t users_htable_vector = 0; 62 | 63 | static spinlock_t *create_session_lock; 64 | 65 | static DEFINE_SPINLOCK(sessions_timer_lock); 66 | static DEFINE_SPINLOCK(users_timer_lock); 67 | static struct timer_list sessions_cleanup_timer, users_cleanup_timer, nf_send_timer; 68 | 69 | struct proc_dir_entry *proc_net_nat; 70 | 71 | struct netflow_sock { 72 | struct list_head list; 73 | struct socket *sock; 74 | struct sockaddr_storage addr; // destination 75 | }; 76 | 77 | struct xt_nat_htable { 78 | uint8_t use; 79 | spinlock_t lock; 80 | struct hlist_head session; 81 | }; 82 | 83 | struct nat_htable_ent { 84 | struct rcu_head rcu; 85 | struct hlist_node list_node; 86 | uint8_t proto; 87 | uint32_t addr; 88 | uint16_t port; 89 | struct nat_session *data; 90 | }; 91 | 92 | struct nat_session { 93 | uint32_t in_addr; 94 | uint16_t in_port; 95 | uint16_t out_port; 96 | int16_t timeout; 97 | uint8_t flags; 98 | }; 99 | 100 | struct xt_users_htable { 101 | uint8_t use; 102 | spinlock_t lock; 103 | struct hlist_head user; 104 | }; 105 | 106 | struct user_htable_ent { 107 | struct rcu_head rcu; 108 | struct hlist_node list_node; 109 | uint32_t addr; 110 | uint16_t tcp_count; 111 | uint16_t udp_count; 112 | uint16_t other_count; 113 | uint8_t idle; 114 | }; 115 | 116 | struct xt_users_htable *ht_users; 117 | 118 | static u_int32_t nat_pool_start; 119 | static u_int32_t nat_pool_end; 120 | 121 | struct xt_nat_htable *ht_inner, *ht_outer; 122 | 123 | static char *print_sockaddr(const struct sockaddr_storage *ss) 124 | { 125 | static char buf[64]; 126 | snprintf(buf, sizeof(buf), "%pISpc", ss); 127 | return buf; 128 | } 129 | 130 | static inline long timer_end(struct timespec start_time) 131 | { 132 | struct timespec end_time; 133 | getrawmonotonic(&end_time); 134 | return(end_time.tv_nsec - start_time.tv_nsec); 135 | } 136 | 137 | static inline struct timespec timer_start(void) 138 | { 139 | struct timespec start_time; 140 | getrawmonotonic(&start_time); 141 | return start_time; 142 | } 143 | 144 | static inline u_int32_t 145 | get_pool_size(void) 146 | { 147 | return ntohl(nat_pool_end)-ntohl(nat_pool_start)+1; 148 | } 149 | 150 | static inline u_int32_t 151 | get_nat_addr(const u_int32_t addr) 152 | { 153 | return htonl(ntohl(nat_pool_start)+reciprocal_scale(jhash_1word(addr, 0), get_pool_size())); 154 | } 155 | 156 | static inline u_int32_t 157 | get_hash_nat_ent(const uint8_t proto, const u_int32_t addr, const uint16_t port) 158 | { 159 | return reciprocal_scale(jhash_3words((u32)proto, addr, (u32)port, 0), nat_hash_size); 160 | } 161 | 162 | static inline u_int32_t 163 | get_hash_user_ent(const u_int32_t addr) 164 | { 165 | return reciprocal_scale(jhash_1word(addr, 0), users_hash_size); 166 | } 167 | 168 | static inline u_int32_t pool_table_create(void) 169 | { 170 | unsigned int sz; /* (bytes) */ 171 | unsigned int pool_size; 172 | int i; 173 | 174 | pool_size = get_pool_size(); 175 | 176 | sz = sizeof(spinlock_t) * pool_size; 177 | create_session_lock = kzalloc(sz, GFP_KERNEL); 178 | 179 | if (create_session_lock == NULL) 180 | return -ENOMEM; 181 | 182 | for (i = 0; i < pool_size; i++) { 183 | spin_lock_init(&create_session_lock[i]); 184 | } 185 | 186 | printk(KERN_INFO "xt_NAT DEBUG: nat pool table mem: %d\n", sz); 187 | 188 | return 0; 189 | } 190 | 191 | void pool_table_remove(void) 192 | { 193 | kfree(create_session_lock); 194 | 195 | printk(KERN_INFO "xt_NAT pool_table_remove DEBUG: removed\n"); 196 | } 197 | 198 | 199 | static int users_htable_create(void) 200 | { 201 | unsigned int sz; /* (bytes) */ 202 | int i; 203 | 204 | sz = sizeof(struct xt_users_htable) * users_hash_size; 205 | ht_users = kzalloc(sz, GFP_KERNEL); 206 | 207 | if (ht_users == NULL) 208 | return -ENOMEM; 209 | 210 | for (i = 0; i < users_hash_size; i++) { 211 | spin_lock_init(&ht_users[i].lock); 212 | INIT_HLIST_HEAD(&ht_users[i].user); 213 | ht_users[i].use = 0; 214 | } 215 | 216 | printk(KERN_INFO "xt_NAT DEBUG: users htable mem: %d\n", sz); 217 | return 0; 218 | } 219 | 220 | void users_htable_remove(void) 221 | { 222 | struct user_htable_ent *user; 223 | struct hlist_head *head; 224 | struct hlist_node *next; 225 | int i; 226 | 227 | for (i = 0; i < users_hash_size; i++) { 228 | spin_lock_bh(&ht_users[i].lock); 229 | head = &ht_users[i].user; 230 | hlist_for_each_entry_safe(user, next, head, list_node) { 231 | hlist_del_rcu(&user->list_node); 232 | ht_users[i].use--; 233 | kfree_rcu(user, rcu); 234 | } 235 | 236 | if (ht_users[i].use != 0) { 237 | printk(KERN_WARNING "xt_NAT users_htable_remove ERROR: bad use value: %d in element %d\n", ht_users[i].use, i); 238 | } 239 | spin_unlock_bh(&ht_users[i].lock); 240 | } 241 | kfree(ht_users); 242 | printk(KERN_INFO "xt_NAT users_htable_remove DONE\n"); 243 | return; 244 | } 245 | 246 | void nat_htable_remove(void) 247 | { 248 | struct nat_htable_ent *session; 249 | struct hlist_head *head; 250 | struct hlist_node *next; 251 | unsigned int i; 252 | void *p; 253 | 254 | for (i = 0; i < nat_hash_size; i++) { 255 | spin_lock_bh(&ht_inner[i].lock); 256 | head = &ht_inner[i].session; 257 | hlist_for_each_entry_safe(session, next, head, list_node) { 258 | hlist_del_rcu(&session->list_node); 259 | ht_inner[i].use--; 260 | kfree_rcu(session, rcu); 261 | } 262 | if (ht_inner[i].use != 0) { 263 | printk(KERN_WARNING "xt_NAT nat_htable_remove inner ERROR: bad use value: %d in element %d\n", ht_inner[i].use, i); 264 | } 265 | spin_unlock_bh(&ht_inner[i].lock); 266 | } 267 | 268 | for (i = 0; i < nat_hash_size; i++) { 269 | spin_lock_bh(&ht_outer[i].lock); 270 | head = &ht_outer[i].session; 271 | hlist_for_each_entry_safe(session, next, head, list_node) { 272 | hlist_del_rcu(&session->list_node); 273 | ht_outer[i].use--; 274 | p = session->data; 275 | kfree_rcu(session, rcu); 276 | kfree(p); 277 | } 278 | if (ht_outer[i].use != 0) { 279 | printk(KERN_WARNING "xt_NAT nat_htable_remove outer ERROR: bad use value: %d in element %d\n", ht_outer[i].use, i); 280 | } 281 | spin_unlock_bh(&ht_outer[i].lock); 282 | } 283 | printk(KERN_INFO "xt_NAT nat_htable_remove DONE\n"); 284 | return; 285 | } 286 | 287 | 288 | static int nat_htable_create(void) 289 | { 290 | unsigned int sz; /* (bytes) */ 291 | int i; 292 | 293 | sz = sizeof(struct xt_nat_htable) * nat_hash_size; 294 | ht_inner = kzalloc(sz, GFP_KERNEL); 295 | if (ht_inner == NULL) 296 | return -ENOMEM; 297 | 298 | for (i = 0; i < nat_hash_size; i++) { 299 | spin_lock_init(&ht_inner[i].lock); 300 | INIT_HLIST_HEAD(&ht_inner[i].session); 301 | ht_inner[i].use = 0; 302 | } 303 | 304 | printk(KERN_INFO "xt_NAT DEBUG: sessions htable inner mem: %d\n", sz); 305 | 306 | 307 | ht_outer = kzalloc(sz, GFP_KERNEL); 308 | if (ht_outer == NULL) 309 | return -ENOMEM; 310 | 311 | for (i = 0; i < nat_hash_size; i++) { 312 | spin_lock_init(&ht_outer[i].lock); 313 | INIT_HLIST_HEAD(&ht_outer[i].session); 314 | ht_outer[i].use = 0; 315 | } 316 | 317 | printk(KERN_INFO "xt_NAT DEBUG: sessions htable outer mem: %d\n", sz); 318 | return 0; 319 | } 320 | 321 | struct nat_htable_ent *lookup_session(struct xt_nat_htable *ht, const uint8_t proto, const u_int32_t addr, const uint16_t port) 322 | { 323 | struct nat_htable_ent *session; 324 | struct hlist_head *head; 325 | unsigned int hash; 326 | 327 | hash = get_hash_nat_ent(proto, addr, port); 328 | if (ht[hash].use == 0) 329 | return NULL; 330 | 331 | head = &ht[hash].session; 332 | hlist_for_each_entry_rcu(session, head, list_node) { 333 | if (session->addr == addr && session->port == port && session->proto == proto && session->data->timeout > 0) { 334 | return session; 335 | } else { 336 | //printk(KERN_DEBUG "xt_NAT lookup_session miss: %d - %pI4:%d\n", session->proto, &session->addr, ntohs(session->port)); 337 | } 338 | } 339 | return NULL; 340 | } 341 | 342 | static uint16_t search_free_l4_port(const uint8_t proto, const u_int32_t nataddr, const uint16_t userport) 343 | { 344 | uint16_t i, freeport; 345 | for(i = 0; i < 64512; i++) { 346 | freeport = ntohs(userport) + i; 347 | 348 | if (freeport < 1024) { 349 | freeport += 1024; 350 | } 351 | 352 | //printk(KERN_DEBUG "xt_NAT search_free_l4_port: check nat port = %d\n", freeport); 353 | 354 | if(!lookup_session(ht_outer, proto, nataddr, htons(freeport))) { 355 | return htons(freeport); 356 | } 357 | } 358 | return 0; 359 | } 360 | 361 | static int check_user_limits(const u_int8_t proto, const u_int32_t addr) 362 | { 363 | struct user_htable_ent *user; 364 | struct hlist_head *head; 365 | unsigned int hash, is_found, ret; 366 | unsigned int sessions, session_limit; 367 | 368 | hash = get_hash_user_ent(addr); 369 | rcu_read_lock_bh(); 370 | head = &ht_users[hash].user; 371 | is_found=0; 372 | hlist_for_each_entry_rcu(user, head, list_node) { 373 | if (user->addr == addr && user->idle < 15) { 374 | //printk(KERN_DEBUG "xt_NAT check_user_limits hit: %pI4\n", &user->addr); 375 | if (proto == IPPROTO_TCP) { 376 | sessions = user->tcp_count; 377 | session_limit = 4096; 378 | } else if (proto == IPPROTO_UDP) { 379 | sessions = user->udp_count; 380 | session_limit = 4096; 381 | } else { 382 | sessions = user->other_count; 383 | session_limit = 4096; 384 | } 385 | is_found=1; 386 | break; 387 | } else { 388 | //printk(KERN_DEBUG "xt_NAT check_user_limits miss: %pI4\n", &user->addr); 389 | } 390 | } 391 | 392 | ret=1; 393 | if (is_found==1) { 394 | //printk(KERN_DEBUG "xt_NAT check_user_limits: sessions = %d of %d\n", sessions, session_limit); 395 | if (sessions < session_limit) { 396 | ret=1; 397 | } else { 398 | ret=0; 399 | } 400 | } else { 401 | //printk(KERN_DEBUG "xt_NAT check_user_limits is not found: %pI4\n", &addr); 402 | ret=1; 403 | } 404 | rcu_read_unlock_bh(); 405 | return ret; 406 | } 407 | 408 | void update_user_limits(const u_int8_t proto, const u_int32_t addr, const int8_t operation) 409 | { 410 | struct user_htable_ent *user; 411 | struct hlist_head *head; 412 | unsigned int hash, is_found; 413 | unsigned int sz; 414 | //u_int32_t nataddr; 415 | 416 | hash = get_hash_user_ent(addr); 417 | spin_lock_bh(&ht_users[hash].lock); 418 | head = &ht_users[hash].user; 419 | is_found=0; 420 | hlist_for_each_entry(user, head, list_node) { 421 | if (user->addr == addr && user->idle < 15) { 422 | //printk(KERN_DEBUG "xt_NAT check_user_limits hit: %pI4\n", &user->addr); 423 | is_found=1; 424 | break; 425 | } else { 426 | //printk(KERN_DEBUG "xt_NAT check_user_limits miss: %pI4\n", &user->addr); 427 | } 428 | } 429 | 430 | if (likely(is_found==1)) { 431 | user->idle = 0; 432 | if (proto == IPPROTO_TCP) { 433 | user->tcp_count += operation; 434 | } else if (proto == IPPROTO_UDP) { 435 | user->udp_count += operation; 436 | } else { 437 | user->other_count += operation; 438 | } 439 | } else { 440 | //printk(KERN_DEBUG "xt_NAT update_user_limits is not found: %pI4\n", &addr); 441 | 442 | //printk(KERN_DEBUG "xt_NAT update_user_limits: add user_session entry to htable\n"); 443 | sz = sizeof(struct user_htable_ent); 444 | user = kzalloc(sz, GFP_ATOMIC); 445 | 446 | if (user == NULL) { 447 | printk(KERN_WARNING "xt_NAT update_user_limits ERROR: Cannot allocate memory for user_session\n"); 448 | spin_unlock_bh(&ht_users[hash].lock); 449 | return; 450 | } 451 | 452 | user->addr = addr; 453 | user->tcp_count = 0; 454 | user->udp_count = 0; 455 | user->other_count = 0; 456 | user->idle = 0; 457 | 458 | if (proto == IPPROTO_TCP) { 459 | user->tcp_count += operation; 460 | } else if (proto == IPPROTO_UDP) { 461 | user->udp_count += operation; 462 | } else { 463 | user->other_count += operation; 464 | } 465 | hlist_add_head_rcu(&user->list_node, &ht_users[hash].user); 466 | ht_users[hash].use++; 467 | atomic64_inc(&users_active); 468 | 469 | //nataddr = get_nat_addr(user->addr); 470 | //printk(KERN_DEBUG "xt_NAT NEW: %pI4 -> %pI4\n", &user->addr, &nataddr); 471 | } 472 | 473 | spin_unlock_bh(&ht_users[hash].lock); 474 | return; 475 | } 476 | 477 | /* socket code */ 478 | static void sk_error_report(struct sock *sk) 479 | { 480 | /* clear connection refused errors if any */ 481 | sk->sk_err = 0; 482 | 483 | return; 484 | } 485 | 486 | static struct socket *usock_open_sock(const struct sockaddr_storage *addr, void *user_data) 487 | { 488 | struct socket *sock; 489 | int error; 490 | 491 | if ((error = sock_create_kern(addr->ss_family, SOCK_DGRAM, IPPROTO_UDP, &sock)) < 0) { 492 | printk(KERN_WARNING "xt_NAT NEL: sock_create_kern error %d\n", -error); 493 | return NULL; 494 | } 495 | sock->sk->sk_allocation = GFP_ATOMIC; 496 | sock->sk->sk_prot->unhash(sock->sk); /* hidden from input */ 497 | sock->sk->sk_error_report = &sk_error_report; /* clear ECONNREFUSED */ 498 | sock->sk->sk_user_data = user_data; /* usock */ 499 | 500 | if (sndbuf < SOCK_MIN_SNDBUF) 501 | sndbuf = SOCK_MIN_SNDBUF; 502 | 503 | if (sndbuf) 504 | sock->sk->sk_sndbuf = sndbuf; 505 | else 506 | sndbuf = sock->sk->sk_sndbuf; 507 | error = sock->ops->connect(sock, (struct sockaddr *)addr, sizeof(*addr), 0); 508 | if (error < 0) { 509 | printk(KERN_WARNING "xt_NAT NEL: error connecting UDP socket %d," 510 | " don't worry, will try reconnect later.\n", -error); 511 | /* ENETUNREACH when no interfaces */ 512 | sock_release(sock); 513 | return NULL; 514 | } 515 | return sock; 516 | } 517 | 518 | static void netflow_sendmsg(void *buffer, const int len) 519 | { 520 | struct msghdr msg = { .msg_flags = MSG_DONTWAIT|MSG_NOSIGNAL }; 521 | struct kvec iov = { buffer, len }; 522 | struct netflow_sock *usock; 523 | int ret; 524 | 525 | //printk(KERN_DEBUG "xt_NAT NEL: Netflow exporting function\n"); 526 | 527 | list_for_each_entry(usock, &usock_list, list) { 528 | //printk(KERN_DEBUG "xt_NAT NEL: Exporting PDU to collector N\n"); 529 | if (!usock->sock) 530 | usock->sock = usock_open_sock(&usock->addr, usock); 531 | 532 | if (!usock->sock) 533 | continue; 534 | 535 | ret = kernel_sendmsg(usock->sock, &msg, &iov, 1, (size_t)len); 536 | if (ret == -EINVAL) { 537 | if (usock->sock) 538 | sock_release(usock->sock); 539 | usock->sock = NULL; 540 | } else if (ret == -EAGAIN) { 541 | printk(KERN_WARNING "xt_NAT NEL: increase sndbuf!\n"); 542 | } 543 | } 544 | } 545 | 546 | static void netflow_export_pdu_v5(void) 547 | { 548 | struct timeval tv; 549 | int pdusize; 550 | 551 | //printk(KERN_DEBUG "xt_NAT NEL: Forming PDU seq %d, %d records\n", pdu_seq, pdu_data_records); 552 | 553 | if (!pdu_data_records) 554 | return; 555 | 556 | pdu.version = htons(5); 557 | pdu.nr_records = htons(pdu_data_records); 558 | pdu.ts_uptime = htonl(jiffies_to_msecs(jiffies)); 559 | do_gettimeofday(&tv); 560 | pdu.ts_usecs = htonl(tv.tv_sec); 561 | pdu.ts_unsecs = htonl(tv.tv_usec); 562 | pdu.seq = htonl(pdu_seq); 563 | //pdu.v5.eng_type = 0; 564 | pdu.eng_id = (__u8)engine_id; 565 | 566 | pdusize = NETFLOW5_HEADER_SIZE + sizeof(struct netflow5_record) * pdu_data_records; 567 | 568 | netflow_sendmsg(&pdu, pdusize); 569 | 570 | pdu_seq += pdu_data_records; 571 | pdu_data_records = 0; 572 | } 573 | 574 | static void netflow_export_flow_v5(const uint8_t proto, const u_int32_t useraddr, const uint16_t userport, const u_int32_t nataddr, const uint16_t natport, const int flags) 575 | { 576 | struct netflow5_record *rec; 577 | 578 | spin_lock_bh(&nfsend_lock); 579 | 580 | rec = &pdu.flow[pdu_data_records++]; 581 | 582 | /* make V5 flow record */ 583 | rec->s_addr = useraddr; 584 | rec->d_addr = nataddr; 585 | rec->nexthop = nataddr; 586 | rec->i_ifc = 0; 587 | rec->o_ifc = 0; 588 | rec->nr_packets = 0; 589 | rec->nr_octets = 0; 590 | rec->first_ms = htonl(jiffies_to_msecs(jiffies)); 591 | rec->last_ms = htonl(jiffies_to_msecs(jiffies)); 592 | rec->s_port = userport; 593 | rec->d_port = natport; 594 | //rec->reserved = 0; /* pdu is always zeroized for v5 in netflow_switch_version */ 595 | if (flags == 0) { 596 | rec->tcp_flags = TCP_SYN_ACK; 597 | } else { 598 | rec->tcp_flags = TCP_FIN_RST; 599 | } 600 | rec->protocol = proto; 601 | rec->tos = 0; 602 | rec->s_as = userport; 603 | rec->d_as = natport; 604 | rec->s_mask = 0; 605 | rec->d_mask = 0; 606 | //rec->padding = 0; 607 | 608 | //printk(KERN_DEBUG "xt_NAT NEL: Add flow %pI4:%d (outside %pI4:%d) to PDU\n", &useraddr, ntohs(userport), &nataddr, ntohs(natport)); 609 | 610 | if (pdu_data_records == NETFLOW5_RECORDS_MAX) 611 | netflow_export_pdu_v5(); 612 | 613 | spin_unlock_bh(&nfsend_lock); 614 | } 615 | 616 | struct nat_htable_ent *create_nat_session(const uint8_t proto, const u_int32_t useraddr, const uint16_t userport, const u_int32_t nataddr) 617 | { 618 | unsigned int hash; 619 | struct nat_htable_ent *session, *session2; 620 | struct nat_session *data_session; 621 | uint16_t natport; 622 | unsigned int sz; 623 | unsigned int nataddr_id; 624 | 625 | atomic64_inc(&sessions_tried); 626 | 627 | if (unlikely(check_user_limits(proto, useraddr) == 0)) { 628 | printk(KERN_NOTICE "xt_NAT: %pI4 exceed max allowed sessions\n", &useraddr); 629 | return NULL; 630 | } 631 | 632 | nataddr_id = ntohl(nataddr) - ntohl(nat_pool_start); 633 | //printk(KERN_DEBUG "xt_NAT create_nat_session: nataddr_id = %u (%u - %u)\n", nataddr_id, ntohl(nataddr), ntohl(nat_pool_start)); 634 | spin_lock_bh(&create_session_lock[nataddr_id]); 635 | 636 | rcu_read_lock_bh(); 637 | session = lookup_session(ht_inner, proto, useraddr, userport); 638 | if(unlikely(session)) { 639 | //printk(KERN_DEBUG "xt_NAT create_nat_session WARN: Race Condition found\n"); 640 | spin_unlock_bh(&create_session_lock[nataddr_id]); 641 | return lookup_session(ht_outer, proto, nataddr, session->data->out_port); //тут без потери, но с нюансами внутри nat_tg 642 | } 643 | rcu_read_unlock_bh(); 644 | 645 | if (likely(proto == IPPROTO_TCP || proto == IPPROTO_UDP || proto == IPPROTO_ICMP)) { 646 | rcu_read_lock_bh(); 647 | natport = search_free_l4_port(proto, nataddr, userport); 648 | rcu_read_unlock_bh(); 649 | if (natport == 0) { 650 | printk(KERN_WARNING "xt_NAT create_nat_session ERROR: Not found free nat port for %d %pI4:%u -> %pI4:XXXX\n", proto, &useraddr, userport, &nataddr); 651 | spin_unlock_bh(&create_session_lock[nataddr_id]); 652 | return NULL; 653 | } 654 | } else { 655 | natport = userport; 656 | } 657 | 658 | sz = sizeof(struct nat_session); 659 | data_session = kzalloc(sz, GFP_ATOMIC); 660 | 661 | if (unlikely(data_session == NULL)) { 662 | printk(KERN_WARNING "xt_NAT create_nat_session ERROR: Cannot allocate memory for data_session\n"); 663 | spin_unlock_bh(&create_session_lock[nataddr_id]); 664 | return NULL; 665 | } 666 | 667 | sz = sizeof(struct nat_htable_ent); 668 | session = kzalloc(sz, GFP_ATOMIC); 669 | 670 | if (unlikely(session == NULL)) { 671 | printk(KERN_WARNING "xt_NAT ERROR: Cannot allocate memory for ht_inner session\n"); 672 | kfree(data_session); 673 | spin_unlock_bh(&create_session_lock[nataddr_id]); 674 | return NULL; 675 | } 676 | 677 | sz = sizeof(struct nat_htable_ent); 678 | session2 = kzalloc(sz, GFP_ATOMIC); 679 | 680 | if (unlikely(session2 == NULL)) { 681 | printk(KERN_WARNING "xt_NAT ERROR: Cannot allocate memory for ht_outer session\n"); 682 | kfree(data_session); 683 | kfree(session); 684 | spin_unlock_bh(&create_session_lock[nataddr_id]); 685 | return NULL; 686 | } 687 | 688 | data_session->in_addr = useraddr; 689 | data_session->in_port = userport; 690 | data_session->out_port = natport; 691 | //data_session->timeout = 600; 692 | data_session->timeout = 30; 693 | data_session->flags = 0; 694 | 695 | session->proto = proto; 696 | session->addr = useraddr; 697 | session->port = userport; 698 | session->data = data_session; 699 | 700 | session2->proto = proto; 701 | session2->addr = nataddr; 702 | session2->port = natport; 703 | session2->data = data_session; 704 | 705 | hash = get_hash_nat_ent(proto, useraddr, userport); 706 | spin_lock_bh(&ht_inner[hash].lock); 707 | hlist_add_head_rcu(&session->list_node, &ht_inner[hash].session); 708 | ht_inner[hash].use++; 709 | spin_unlock_bh(&ht_inner[hash].lock); 710 | 711 | hash = get_hash_nat_ent(proto, nataddr, natport); 712 | spin_lock_bh(&ht_outer[hash].lock); 713 | hlist_add_head_rcu(&session2->list_node, &ht_outer[hash].session); 714 | ht_outer[hash].use++; 715 | spin_unlock_bh(&ht_outer[hash].lock); 716 | 717 | spin_unlock_bh(&create_session_lock[nataddr_id]); 718 | 719 | update_user_limits(proto, useraddr, 1); 720 | 721 | netflow_export_flow_v5(proto, useraddr, userport, nataddr, natport, 0); 722 | 723 | atomic64_inc(&sessions_created); 724 | atomic64_inc(&sessions_active); 725 | //printk(KERN_DEBUG "xt_NAT NEW SESSION: %d %pI4:%u -> %pI4:%u\n", session2->proto, &session2->data->in_addr, ntohs(session2->data->in_port), &session2->addr, ntohs(session2->port)); 726 | rcu_read_lock_bh(); 727 | return lookup_session(ht_outer, proto, nataddr, natport); 728 | } 729 | 730 | static unsigned int 731 | nat_tg(struct sk_buff *skb, const struct xt_action_param *par) 732 | { 733 | struct iphdr *ip; 734 | struct tcphdr *tcp; 735 | struct udphdr *udp; 736 | struct icmphdr *icmp; 737 | struct nat_htable_ent *session; 738 | uint32_t nat_addr; 739 | uint16_t nat_port; 740 | skb_frag_t *frag; 741 | const struct xt_nat_tginfo *info = par->targinfo; 742 | 743 | if (unlikely(skb->protocol != htons(ETH_P_IP))) { 744 | printk(KERN_DEBUG "xt_NAT DEBUG: Drop not IP packet\n"); 745 | return NF_DROP; 746 | } 747 | if (unlikely(ip_hdrlen(skb) != sizeof(struct iphdr))) { 748 | printk(KERN_DEBUG "xt_NAT DEBUG: Drop truncated IP packet\n"); 749 | return NF_DROP; 750 | } 751 | 752 | ip = (struct iphdr *)skb_network_header(skb); 753 | 754 | if (unlikely(ip->frag_off & htons(IP_OFFSET))) { 755 | printk(KERN_DEBUG "xt_NAT DEBUG: Drop fragmented IP packet\n"); 756 | return NF_DROP; 757 | } 758 | if (unlikely(ip->version != 4)) { 759 | printk(KERN_DEBUG "xt_NAT DEBUG: Drop not IPv4 IP packet\n"); 760 | return NF_DROP; 761 | } 762 | 763 | if (info->variant == XTNAT_SNAT) { 764 | nat_addr = get_nat_addr(ip->saddr); 765 | //printk(KERN_DEBUG "xt_NAT SNAT: tg = SNAT, outer NAT IP = %pI4", &nat_addr); 766 | //printk(KERN_DEBUG "xt_NAT SNAT: check IPv4 packet with src ip = %pI4 and dst ip = %pI4\n", &ip->saddr, &ip->daddr); 767 | 768 | if (ip->protocol == IPPROTO_TCP) { 769 | if (unlikely(skb->len < ip_hdrlen(skb) + sizeof(struct tcphdr))) { 770 | printk(KERN_DEBUG "xt_NAT SNAT: Drop truncated TCP packet\n"); 771 | return NF_DROP; 772 | } 773 | skb_set_transport_header(skb, ip->ihl * 4); 774 | tcp = (struct tcphdr *)skb_transport_header(skb); 775 | skb_reset_transport_header(skb); 776 | 777 | //printk(KERN_DEBUG "xt_NAT SNAT: TCP packet with src port = %d\n", ntohs(tcp->source)); 778 | rcu_read_lock_bh(); 779 | session = lookup_session(ht_inner, ip->protocol, ip->saddr, tcp->source); 780 | if (session) { 781 | //printk(KERN_DEBUG "xt_NAT SNAT: found session for src ip = %pI4 and src port = %d and nat port = %d\n", &ip->saddr, ntohs(tcp->source), ntohs(session->data->out_port)); 782 | 783 | csum_replace4(&ip->check, ip->saddr, nat_addr); 784 | inet_proto_csum_replace4(&tcp->check, skb, ip->saddr, nat_addr, true); 785 | inet_proto_csum_replace2(&tcp->check, skb, tcp->source, session->data->out_port, true); 786 | 787 | ip->saddr = nat_addr; 788 | tcp->source = session->data->out_port; 789 | 790 | /* if (session->data->flags & FLAG_TCP_CLOSED) { 791 | session->data->timeout=5; 792 | } else if (tcp->rst || tcp->fin) { 793 | session->data->flags |= FLAG_TCP_CLOSED; 794 | session->data->timeout=5; 795 | } else 796 | 797 | */ 798 | if (tcp->fin || tcp->rst) { 799 | session->data->timeout=10; 800 | session->data->flags |= FLAG_TCP_FIN; 801 | } else if (session->data->flags & FLAG_TCP_FIN) { 802 | session->data->timeout=10; 803 | session->data->flags &= ~FLAG_TCP_FIN; 804 | } else if ((session->data->flags & FLAG_REPLIED) == 0) { 805 | session->data->timeout=30; 806 | } else { 807 | session->data->timeout=300; 808 | } 809 | 810 | /* 811 | if ((session->data->flags & FLAG_REPLIED) == 0) { 812 | session->data->timeout=30; 813 | } else { 814 | session->data->timeout=300; 815 | } 816 | */ 817 | 818 | rcu_read_unlock_bh(); 819 | } else { 820 | rcu_read_unlock_bh(); 821 | //printk(KERN_DEBUG "xt_NAT SNAT: NOT found session for src ip = %pI4 and src port = %d\n", &ip->saddr, ntohs(tcp->source)); 822 | 823 | /* if (!tcp->syn) { 824 | //printk(KERN_DEBUG "xt_NAT SNAT: SYN flag is not set. Dropping packet\n"); 825 | return NF_DROP; 826 | } 827 | */ 828 | session = create_nat_session(ip->protocol, ip->saddr, tcp->source, nat_addr); 829 | if (session == NULL) { 830 | printk(KERN_NOTICE "xt_NAT SNAT: Cannot create new session. Dropping packet\n"); 831 | return NF_DROP; 832 | } 833 | 834 | csum_replace4(&ip->check, ip->saddr, session->addr); 835 | inet_proto_csum_replace4(&tcp->check, skb, ip->saddr, session->addr, true); 836 | inet_proto_csum_replace2(&tcp->check, skb, session->data->in_port, session->data->out_port, true); 837 | ip->saddr = session->addr; 838 | tcp->source = session->data->out_port; 839 | rcu_read_unlock_bh(); 840 | //return NF_ACCEPT; 841 | } 842 | 843 | } else if (ip->protocol == IPPROTO_UDP) { 844 | if (unlikely(skb->len < ip_hdrlen(skb) + sizeof(struct udphdr))) { 845 | printk(KERN_DEBUG "xt_NAT SNAT: Drop truncated UDP packet\n"); 846 | return NF_DROP; 847 | } 848 | 849 | skb_set_transport_header(skb, ip->ihl * 4); 850 | udp = (struct udphdr *)skb_transport_header(skb); 851 | skb_reset_transport_header(skb); 852 | 853 | //printk(KERN_DEBUG "xt_NAT SNAT: UDP packet with src port = %d\n", ntohs(udp->source)); 854 | 855 | rcu_read_lock_bh(); 856 | session = lookup_session(ht_inner, ip->protocol, ip->saddr, udp->source); 857 | if (session) { 858 | //printk(KERN_DEBUG "xt_NAT SNAT: found session for src ip = %pI4 and src port = %d and nat port = %d\n", &ip->saddr, ntohs(udp->source), ntohs(session->data->out_port)); 859 | 860 | csum_replace4(&ip->check, ip->saddr, nat_addr); 861 | if (udp->check) { 862 | inet_proto_csum_replace4(&udp->check, skb, ip->saddr, nat_addr, true); 863 | inet_proto_csum_replace2(&udp->check, skb, udp->source, session->data->out_port, true); 864 | } 865 | 866 | ip->saddr = nat_addr; 867 | udp->source = session->data->out_port; 868 | 869 | if ((session->data->flags & FLAG_REPLIED) == 0) { 870 | session->data->timeout=30; 871 | } else { 872 | session->data->timeout=300; 873 | } 874 | rcu_read_unlock_bh(); 875 | } else { 876 | rcu_read_unlock_bh(); 877 | //printk(KERN_DEBUG "xt_NAT SNAT: NOT found session for src ip = %pI4 and src port = %d\n", &ip->saddr, ntohs(udp->source)); 878 | 879 | session = create_nat_session(ip->protocol, ip->saddr, udp->source, nat_addr); 880 | if (session == NULL) { 881 | printk(KERN_NOTICE "xt_NAT SNAT: Cannot create new session. Dropping packet\n"); 882 | return NF_DROP; 883 | } 884 | 885 | csum_replace4(&ip->check, ip->saddr, session->addr); 886 | if (udp->check) { 887 | inet_proto_csum_replace4(&udp->check, skb, ip->saddr, session->addr, true); 888 | inet_proto_csum_replace2(&udp->check, skb, session->data->in_port, session->data->out_port, true); 889 | } 890 | ip->saddr = session->addr; 891 | udp->source = session->data->out_port; 892 | rcu_read_unlock_bh(); 893 | //return NF_ACCEPT; 894 | } 895 | } else if (ip->protocol == IPPROTO_ICMP) { 896 | if (unlikely(skb->len < ip_hdrlen(skb) + sizeof(struct icmphdr))) { 897 | printk(KERN_DEBUG "xt_NAT SNAT: Drop truncated ICMP packet\n"); 898 | return NF_DROP; 899 | } 900 | 901 | skb_set_transport_header(skb, ip->ihl * 4); 902 | icmp = (struct icmphdr *)skb_transport_header(skb); 903 | skb_reset_transport_header(skb); 904 | 905 | //printk(KERN_DEBUG "xt_NAT SNAT: ICMP packet with type = %d and code = %d\n", icmp->type, icmp->code); 906 | 907 | nat_port = 0; 908 | if (icmp->type == 0 || icmp->type == 8) { 909 | nat_port = icmp->un.echo.id; 910 | } else if (icmp->type == 3 || icmp->type == 4 || icmp->type == 5 || icmp->type == 11 || icmp->type == 12 || icmp->type == 31) { 911 | 912 | } 913 | 914 | rcu_read_lock_bh(); 915 | session = lookup_session(ht_inner, ip->protocol, ip->saddr, nat_port); 916 | if (session) { 917 | //printk(KERN_DEBUG "xt_NAT SNAT: found session for src ip = %pI4 and icmp id = %d\n", &ip->saddr, ntohs(nat_port)); 918 | 919 | csum_replace4(&ip->check, ip->saddr, nat_addr); 920 | 921 | ip->saddr = nat_addr; 922 | 923 | if (icmp->type == 0 || icmp->type == 8) { 924 | inet_proto_csum_replace2(&icmp->checksum, skb, nat_port, session->data->out_port, true); 925 | icmp->un.echo.id = session->data->out_port; 926 | } 927 | 928 | if ((session->data->flags & FLAG_REPLIED) == 0) { 929 | session->data->timeout=30; 930 | } else { 931 | session->data->timeout=30; 932 | } 933 | rcu_read_unlock_bh(); 934 | } else { 935 | rcu_read_unlock_bh(); 936 | //printk(KERN_DEBUG "xt_NAT SNAT: NOT found session for src ip = %pI4 and icmp id = %d\n",&ip->saddr, ntohs(nat_port)); 937 | 938 | session = create_nat_session(ip->protocol, ip->saddr, nat_port, nat_addr); 939 | if (session == NULL) { 940 | printk(KERN_NOTICE "xt_NAT SNAT: Cannot create new session. Dropping packet\n"); 941 | return NF_DROP; 942 | } 943 | 944 | csum_replace4(&ip->check, ip->saddr, session->addr); 945 | ip->saddr = session->addr; 946 | 947 | if (icmp->type == 0 || icmp->type == 8) { 948 | inet_proto_csum_replace2(&icmp->checksum, skb, nat_port, session->data->out_port, true); 949 | icmp->un.echo.id = session->data->out_port; 950 | } 951 | rcu_read_unlock_bh(); 952 | //return NF_ACCEPT; 953 | } 954 | } else { 955 | //skb_set_transport_header(skb, ip->ihl * 4); 956 | 957 | //printk(KERN_DEBUG "xt_NAT SNAT: Generic IP packet\n"); 958 | 959 | rcu_read_lock_bh(); 960 | session = lookup_session(ht_inner, ip->protocol, ip->saddr, 0); 961 | if (session) { 962 | //printk(KERN_DEBUG "xt_NAT SNAT: found session for src ip = %pI4\n", &ip->saddr); 963 | 964 | csum_replace4(&ip->check, ip->saddr, nat_addr); 965 | 966 | ip->saddr = nat_addr; 967 | 968 | if ((session->data->flags & FLAG_REPLIED) == 0) { 969 | session->data->timeout=30; 970 | } else { 971 | session->data->timeout=300; 972 | } 973 | rcu_read_unlock_bh(); 974 | } else { 975 | rcu_read_unlock_bh(); 976 | //printk(KERN_DEBUG "xt_NAT SNAT: NOT found session for src ip = %pI4\n",&ip->saddr); 977 | 978 | session = create_nat_session(ip->protocol, ip->saddr, 0, nat_addr); 979 | if (session == NULL) { 980 | printk(KERN_NOTICE "xt_NAT SNAT: Cannot create new session. Dropping packet\n"); 981 | return NF_DROP; 982 | } 983 | 984 | csum_replace4(&ip->check, ip->saddr, session->addr); 985 | ip->saddr = session->addr; 986 | rcu_read_unlock_bh(); 987 | //return NF_ACCEPT; 988 | } 989 | } 990 | } else if (info->variant == XTNAT_DNAT) { 991 | //printk(KERN_DEBUG "xt_NAT DNAT: tg = DNAT, outer NAT IP = %pI4", &ip->daddr); 992 | //printk(KERN_DEBUG "xt_NAT DNAT: check IPv4 packet with src ip = %pI4 and dst nat ip = %pI4\n", &ip->saddr, &ip->daddr); 993 | 994 | if (ip->protocol == IPPROTO_TCP) { 995 | if (unlikely(skb->len < ip_hdrlen(skb) + sizeof(struct tcphdr))) { 996 | printk(KERN_DEBUG "xt_NAT DNAT: Drop truncated TCP packet\n"); 997 | return NF_DROP; 998 | } 999 | 1000 | skb_set_transport_header(skb, ip->ihl * 4); 1001 | tcp = (struct tcphdr *)skb_transport_header(skb); 1002 | skb_reset_transport_header(skb); 1003 | 1004 | if (unlikely(skb_shinfo(skb)->nr_frags > 1 && skb_headlen(skb) == sizeof(struct iphdr))) { 1005 | frag = &skb_shinfo(skb)->frags[0]; 1006 | //printk(KERN_DEBUG "xt_NAT DNAT: frag_size = %d (required %lu)\n", frag->size, sizeof(struct tcphdr)); 1007 | if (unlikely(frag->size < sizeof(struct tcphdr))) { 1008 | printk(KERN_DEBUG "xt_NAT DNAT: drop TCP frag_size = %d\n", frag->size); 1009 | return NF_DROP; 1010 | } 1011 | tcp = (struct tcphdr *)skb_frag_address_safe(frag); 1012 | if (unlikely(tcp == NULL)) { 1013 | printk(KERN_DEBUG "xt_NAT DNAT: drop fragmented TCP\n"); 1014 | return NF_DROP; 1015 | } 1016 | atomic64_inc(&frags); 1017 | } 1018 | 1019 | //printk(KERN_DEBUG "xt_NAT DNAT: TCP packet with dst port = %d\n", ntohs(tcp->dest)); 1020 | 1021 | rcu_read_lock_bh(); 1022 | session = lookup_session(ht_outer, ip->protocol, ip->daddr, tcp->dest); 1023 | if (likely(session)) { 1024 | //printk(KERN_DEBUG "xt_NAT DNAT: found session for src ip = %pI4 and src port = %d and nat port = %d\n", &session->data->in_addr, ntohs(session->data->in_port), ntohs(tcp->dest)); 1025 | csum_replace4(&ip->check, ip->daddr, session->data->in_addr); 1026 | inet_proto_csum_replace4(&tcp->check, skb, ip->daddr, session->data->in_addr, true); 1027 | inet_proto_csum_replace2(&tcp->check, skb, tcp->dest, session->data->in_port, true); 1028 | ip->daddr = session->data->in_addr; 1029 | tcp->dest = session->data->in_port; 1030 | 1031 | if (tcp->fin || tcp->rst) { 1032 | session->data->timeout=10; 1033 | session->data->flags |= FLAG_TCP_FIN; 1034 | } else if (session->data->flags & FLAG_TCP_FIN) { 1035 | session->data->timeout=10; 1036 | session->data->flags &= ~FLAG_TCP_FIN; 1037 | } else if ((session->data->flags & FLAG_REPLIED) == 0) { 1038 | //printk(KERN_DEBUG "xt_NAT DNAT: Changing state from UNREPLIED to REPLIED\n"); 1039 | session->data->timeout=300; 1040 | session->data->flags |= FLAG_REPLIED; 1041 | } 1042 | 1043 | /* if (((session->data->flags & FLAG_TCP_CLOSED) == 0) && (tcp->rst || tcp->fin)) { 1044 | session->data->flags |= FLAG_TCP_CLOSED; 1045 | session->data->timeout=5; 1046 | } else if (((session->data->flags & FLAG_REPLIED) == 0) && (session->data->flags & FLAG_TCP_CLOSED) == 0) { 1047 | //printk(KERN_DEBUG "xt_NAT DNAT: Changing state from UNREPLIED to REPLIED\n"); 1048 | session->data->timeout=300; 1049 | session->data->flags |= FLAG_REPLIED; 1050 | } 1051 | */ 1052 | /* if ((session->data->flags & FLAG_REPLIED) == 0 && (tcp->rst || tcp->fin)) { 1053 | session->data->timeout=5; 1054 | } else if ((session->data->flags & FLAG_REPLIED) == 0) { 1055 | //printk(KERN_DEBUG "xt_NAT DNAT: Changing state from UNREPLIED to REPLIED\n"); 1056 | session->data->timeout=300; 1057 | session->data->flags |= FLAG_REPLIED; 1058 | } 1059 | */ 1060 | /* 1061 | if ((session->data->flags & FLAG_REPLIED) == 0) { 1062 | //printk(KERN_DEBUG "xt_NAT DNAT: Changing state from UNREPLIED to REPLIED\n"); 1063 | session->data->timeout=300; 1064 | session->data->flags |= FLAG_REPLIED; 1065 | } 1066 | */ 1067 | //printk(KERN_DEBUG "xt_NAT DNAT: new dst ip = %pI4 and dst port = %d\n", &ip->daddr, ntohs(tcp->dest)); 1068 | //printk(KERN_DEBUG "xt_NAT DNAT: new src ip = %pI4 and src port = %d\n", &ip->saddr, ntohs(tcp->source)); 1069 | rcu_read_unlock_bh(); 1070 | } else { 1071 | rcu_read_unlock_bh(); 1072 | atomic64_inc(&dnat_dropped); 1073 | //printk(KERN_DEBUG "xt_NAT DNAT: NOT found session for nat ip = %pI4 and nat port = %d\n", &ip->daddr, ntohs(tcp->dest)); 1074 | //return NF_DROP; 1075 | } 1076 | } else if (ip->protocol == IPPROTO_UDP) { 1077 | if (unlikely(skb->len < ip_hdrlen(skb) + sizeof(struct udphdr))) { 1078 | printk(KERN_DEBUG "xt_NAT DNAT: Drop truncated UDP packet\n"); 1079 | return NF_DROP; 1080 | } 1081 | 1082 | skb_set_transport_header(skb, ip->ihl * 4); 1083 | udp = (struct udphdr *)skb_transport_header(skb); 1084 | skb_reset_transport_header(skb); 1085 | 1086 | if (unlikely(skb_shinfo(skb)->nr_frags > 1 && skb_headlen(skb) == sizeof(struct iphdr))) { 1087 | frag = &skb_shinfo(skb)->frags[0]; 1088 | //printk(KERN_DEBUG "xt_NAT DNAT: frag_size = %d (required %lu)\n", frag->size, sizeof(struct udphdr)); 1089 | if (unlikely(frag->size < sizeof(struct udphdr))) { 1090 | printk(KERN_DEBUG "xt_NAT DNAT: drop UDP frag_size = %d\n", frag->size); 1091 | return NF_DROP; 1092 | } 1093 | udp = (struct udphdr *)skb_frag_address_safe(frag); 1094 | if (unlikely(udp == NULL)) { 1095 | printk(KERN_DEBUG "xt_NAT DNAT: drop fragmented UDP\n"); 1096 | return NF_DROP; 1097 | } 1098 | atomic64_inc(&frags); 1099 | } 1100 | 1101 | //printk(KERN_DEBUG "xt_NAT DNAT: UDP packet with dst port = %d\n", ntohs(udp->dest)); 1102 | 1103 | rcu_read_lock_bh(); 1104 | session = lookup_session(ht_outer, ip->protocol, ip->daddr, udp->dest); 1105 | if (likely(session)) { 1106 | //printk(KERN_DEBUG "xt_NAT DNAT: found session for src ip = %pI4 and src port = %d and nat port = %d\n", &session->data->in_addr, ntohs(session->data->in_port), ntohs(udp->dest)); 1107 | csum_replace4(&ip->check, ip->daddr, session->data->in_addr); 1108 | if (udp->check) { 1109 | inet_proto_csum_replace4(&udp->check, skb, ip->daddr, session->data->in_addr, true); 1110 | inet_proto_csum_replace2(&udp->check, skb, udp->dest, session->data->in_port, true); 1111 | } 1112 | ip->daddr = session->data->in_addr; 1113 | udp->dest = session->data->in_port; 1114 | 1115 | if ((session->data->flags & FLAG_REPLIED) == 0) { 1116 | //printk(KERN_DEBUG "xt_NAT DNAT: Changing state from UNREPLIED to REPLIED\n"); 1117 | session->data->timeout=300; 1118 | session->data->flags |= FLAG_REPLIED; 1119 | } 1120 | 1121 | //printk(KERN_DEBUG "xt_NAT DNAT: new dst ip = %pI4 and dst port = %d\n", &ip->daddr, ntohs(udp->dest)); 1122 | //printk(KERN_DEBUG "xt_NAT DNAT: new src ip = %pI4 and src port = %d\n", &ip->saddr, ntohs(udp->source)); 1123 | rcu_read_unlock_bh(); 1124 | } else { 1125 | rcu_read_unlock_bh(); 1126 | atomic64_inc(&dnat_dropped); 1127 | //printk(KERN_DEBUG "xt_NAT DNAT: NOT found session for nat ip = %pI4 and nat port = %d\n", &ip->daddr, ntohs(udp->dest)); 1128 | //return NF_DROP; 1129 | } 1130 | } else if (ip->protocol == IPPROTO_ICMP) { 1131 | if (unlikely(skb->len < ip_hdrlen(skb) + sizeof(struct icmphdr))) { 1132 | printk(KERN_DEBUG "xt_NAT DNAT: Drop truncated ICMP packet\n"); 1133 | return NF_DROP; 1134 | } 1135 | 1136 | skb_set_transport_header(skb, ip->ihl * 4); 1137 | icmp = (struct icmphdr *)skb_transport_header(skb); 1138 | skb_reset_transport_header(skb); 1139 | //printk(KERN_DEBUG "xt_NAT DNAT: ICMP packet with type = %d and code = %d\n", icmp->type, icmp->code); 1140 | 1141 | nat_port = 0; 1142 | if (icmp->type == 0 || icmp->type == 8) { 1143 | nat_port = icmp->un.echo.id; 1144 | } else if (icmp->type == 3 || icmp->type == 4 || icmp->type == 5 || icmp->type == 11 || icmp->type == 12 || icmp->type == 31) { 1145 | atomic64_inc(&related_icmp); 1146 | //printk(KERN_DEBUG "xt_NAT DNAT: Len: skb=%d, iphdr=%d\n",skb->len, ip_hdrlen(skb)); 1147 | if (skb->len < ip_hdrlen(skb) + sizeof(struct icmphdr) + sizeof(struct iphdr)) { 1148 | printk(KERN_DEBUG "xt_NAT DNAT: Drop related ICMP packet witch truncated IP header\n"); 1149 | return NF_DROP; 1150 | } 1151 | 1152 | skb_set_network_header(skb,sizeof(struct icmphdr) + sizeof(struct iphdr)); 1153 | ip = (struct iphdr *)skb_network_header(skb); 1154 | skb_reset_network_header(skb); 1155 | 1156 | //printk(KERN_DEBUG "xt_NAT DNAT: Related ICMP\n"); 1157 | //printk(KERN_DEBUG "xt_NAT DNAT: Second IP HDR: proto = %d and saddr = %pI4 and daddr = %pI4\n", ip->protocol, &ip->saddr, &ip->daddr); 1158 | 1159 | if (ip->protocol == IPPROTO_TCP) { 1160 | //printk(KERN_DEBUG "xt_NAT DNAT: Related TCP len: skb=%d, iphdr=%d\n",skb->len, ip_hdrlen(skb)); 1161 | if (skb->len < ip_hdrlen(skb) + sizeof(struct icmphdr) + sizeof(struct iphdr) + 8) { 1162 | printk(KERN_DEBUG "xt_NAT DNAT: Drop related ICMP packet witch truncated TCP header\n"); 1163 | return NF_DROP; 1164 | } 1165 | skb_set_transport_header(skb, (ip->ihl * 4) + sizeof(struct icmphdr) + sizeof(struct iphdr)); 1166 | tcp = (struct tcphdr *)skb_transport_header(skb); 1167 | skb_reset_transport_header(skb); 1168 | //port = tcp->source; 1169 | //printk(KERN_DEBUG "xt_NAT DNAT: TCP packet with source nat port = %d\n", ntohs(tcp->source)); 1170 | rcu_read_lock_bh(); 1171 | session = lookup_session(ht_outer, ip->protocol, ip->saddr, tcp->source); 1172 | if (session) { 1173 | csum_replace4(&ip->check, ip->saddr, session->data->in_addr); 1174 | //inet_proto_csum_replace4(&tcp->check, skb, ip->saddr, session->data->in_addr, true); 1175 | //inet_proto_csum_replace2(&tcp->check, skb, tcp->source, session->data->in_port, true); 1176 | ip->saddr = session->data->in_addr; 1177 | tcp->source = session->data->in_port; 1178 | } else { 1179 | rcu_read_unlock_bh(); 1180 | return NF_ACCEPT; 1181 | } 1182 | 1183 | //skb_reset_network_header(skb); 1184 | ip = (struct iphdr *)skb_network_header(skb); 1185 | 1186 | csum_replace4(&ip->check, ip->daddr, session->data->in_addr); 1187 | ip->daddr = session->data->in_addr; 1188 | rcu_read_unlock_bh(); 1189 | } else if (ip->protocol == IPPROTO_UDP) { 1190 | //printk(KERN_DEBUG "xt_NAT DNAT: Related UDP len: skb=%d, iphdr=%d\n",skb->len, ip_hdrlen(skb)); 1191 | if (skb->len < ip_hdrlen(skb) + sizeof(struct icmphdr) + sizeof(struct iphdr) + 8) { 1192 | printk(KERN_DEBUG "xt_NAT DNAT: Drop related ICMP packet witch truncated UDP header\n"); 1193 | return NF_DROP; 1194 | } 1195 | 1196 | skb_set_transport_header(skb, (ip->ihl * 4) + sizeof(struct icmphdr) + sizeof(struct iphdr)); 1197 | udp = (struct udphdr *)skb_transport_header(skb); 1198 | skb_reset_transport_header(skb); 1199 | //printk(KERN_DEBUG "xt_NAT DNAT: UDP packet with source nat port = %d\n", ntohs(udp->source)); 1200 | 1201 | rcu_read_lock_bh(); 1202 | session = lookup_session(ht_outer, ip->protocol, ip->saddr, udp->source); 1203 | if (session) { 1204 | csum_replace4(&ip->check, ip->saddr, session->data->in_addr); 1205 | //inet_proto_csum_replace4(&tcp->check, skb, ip->saddr, session->data->in_addr, true); 1206 | //inet_proto_csum_replace2(&tcp->check, skb, tcp->source, session->data->in_port, true); 1207 | ip->saddr = session->data->in_addr; 1208 | udp->source = session->data->in_port; 1209 | } else { 1210 | rcu_read_unlock_bh(); 1211 | return NF_ACCEPT; 1212 | } 1213 | 1214 | //skb_reset_network_header(skb); 1215 | ip = (struct iphdr *)skb_network_header(skb); 1216 | 1217 | csum_replace4(&ip->check, ip->daddr, session->data->in_addr); 1218 | ip->daddr = session->data->in_addr; 1219 | rcu_read_unlock_bh(); 1220 | } else if (ip->protocol == IPPROTO_ICMP) { 1221 | if (skb->len < ip_hdrlen(skb) + sizeof(struct icmphdr) + sizeof(struct iphdr) + 8) { 1222 | printk(KERN_DEBUG "xt_NAT DNAT: Drop related ICMP packet witch truncated ICMP header\n"); 1223 | return NF_DROP; 1224 | } 1225 | 1226 | skb_set_transport_header(skb, (ip->ihl * 4) + sizeof(struct icmphdr) + sizeof(struct iphdr)); 1227 | icmp = (struct icmphdr *)skb_transport_header(skb); 1228 | skb_reset_transport_header(skb); 1229 | //printk(KERN_DEBUG "xt_NAT DNAT: ICMP packet\n"); 1230 | 1231 | nat_port = 0; 1232 | if (icmp->type == 0 || icmp->type == 8) { 1233 | nat_port = icmp->un.echo.id; 1234 | } 1235 | 1236 | rcu_read_lock_bh(); 1237 | session = lookup_session(ht_outer, ip->protocol, ip->saddr, nat_port); 1238 | if (session) { 1239 | csum_replace4(&ip->check, ip->saddr, session->data->in_addr); 1240 | //inet_proto_csum_replace4(&tcp->check, skb, ip->saddr, session->data->in_addr, true); 1241 | //inet_proto_csum_replace2(&tcp->check, skb, tcp->source, session->data->in_port, true); 1242 | ip->saddr = session->data->in_addr; 1243 | 1244 | if (icmp->type == 0 || icmp->type == 8) { 1245 | inet_proto_csum_replace2(&icmp->checksum, skb, nat_port, session->data->in_port, true); 1246 | icmp->un.echo.id = session->data->in_port; 1247 | } 1248 | 1249 | } else { 1250 | rcu_read_unlock_bh(); 1251 | return NF_ACCEPT; 1252 | } 1253 | 1254 | //skb_reset_network_header(skb); 1255 | ip = (struct iphdr *)skb_network_header(skb); 1256 | 1257 | csum_replace4(&ip->check, ip->daddr, session->data->in_addr); 1258 | ip->daddr = session->data->in_addr; 1259 | rcu_read_unlock_bh(); 1260 | } 1261 | 1262 | return NF_ACCEPT; 1263 | 1264 | } 1265 | rcu_read_lock_bh(); 1266 | session = lookup_session(ht_outer, ip->protocol, ip->daddr, nat_port); 1267 | if (likely(session)) { 1268 | //printk(KERN_DEBUG "xt_NAT DNAT: found session for src ip = %pI4 and icmp id = %d\n", &session->data->in_addr, ntohs(nat_port)); 1269 | csum_replace4(&ip->check, ip->daddr, session->data->in_addr); 1270 | ip->daddr = session->data->in_addr; 1271 | 1272 | if (icmp->type == 0 || icmp->type == 8) { 1273 | inet_proto_csum_replace2(&icmp->checksum, skb, nat_port, session->data->in_port, true); 1274 | icmp->un.echo.id = session->data->in_port; 1275 | } 1276 | 1277 | if ((session->data->flags & FLAG_REPLIED) == 0) { 1278 | //printk(KERN_DEBUG "xt_NAT DNAT: Changing state from UNREPLIED to REPLIED\n"); 1279 | session->data->timeout=30; 1280 | session->data->flags |= FLAG_REPLIED; 1281 | } 1282 | rcu_read_unlock_bh(); 1283 | 1284 | //printk(KERN_DEBUG "xt_NAT DNAT: new dst ip = %pI4 and icmp id = %d\n", &ip->daddr, ntohs(nat_port)); 1285 | } else { 1286 | rcu_read_unlock_bh(); 1287 | atomic64_inc(&dnat_dropped); 1288 | //printk(KERN_DEBUG "xt_NAT DNAT: NOT found session for nat ip = %pI4 and icmp id = %d\n", &ip->daddr, ntohs(nat_port)); 1289 | //return NF_DROP; 1290 | } 1291 | } else { 1292 | //skb_set_transport_header(skb, ip->ihl * 4); 1293 | //printk(KERN_DEBUG "xt_NAT DNAT: Generic IP packet\n"); 1294 | 1295 | nat_port = 0; 1296 | rcu_read_lock_bh(); 1297 | session = lookup_session(ht_outer, ip->protocol, ip->daddr, nat_port); 1298 | if (likely(session)) { 1299 | //printk(KERN_DEBUG "xt_NAT DNAT: found session for src ip = %pI4 and icmp id = %d\n", &session->data->in_addr, ntohs(nat_port)); 1300 | csum_replace4(&ip->check, ip->daddr, session->data->in_addr); 1301 | ip->daddr = session->data->in_addr; 1302 | 1303 | if ((session->data->flags & FLAG_REPLIED) == 0) { 1304 | //printk(KERN_DEBUG "xt_NAT DNAT: Changing state from UNREPLIED to REPLIED\n"); 1305 | session->data->timeout=300; 1306 | session->data->flags |= FLAG_REPLIED; 1307 | } 1308 | rcu_read_unlock_bh(); 1309 | 1310 | //printk(KERN_DEBUG "xt_NAT DNAT: new dst ip = %pI4\n", &ip->daddr); 1311 | } else { 1312 | rcu_read_unlock_bh(); 1313 | atomic64_inc(&dnat_dropped); 1314 | //printk(KERN_DEBUG "xt_NAT DNAT: NOT found session for nat ip = %pI4\n", &ip->daddr); 1315 | //return NF_DROP; 1316 | } 1317 | } 1318 | } 1319 | 1320 | //printk(KERN_DEBUG "xt_NAT ----------------\n"); 1321 | 1322 | return NF_ACCEPT; 1323 | } 1324 | 1325 | void users_cleanup_timer_callback( unsigned long data ) 1326 | { 1327 | struct user_htable_ent *user; 1328 | struct hlist_head *head; 1329 | struct hlist_node *next; 1330 | unsigned int i; 1331 | u_int32_t vector_start, vector_end; 1332 | 1333 | spin_lock_bh(&users_timer_lock); 1334 | 1335 | if (ht_users == NULL) { 1336 | printk(KERN_WARNING "xt_NAT USERS CLEAN ERROR: Found null ptr for ht_users\n"); 1337 | spin_unlock_bh(&users_timer_lock); 1338 | return; 1339 | } 1340 | 1341 | vector_start = users_htable_vector * (users_hash_size/60); 1342 | if (users_htable_vector == 60) { 1343 | vector_end = users_hash_size; 1344 | users_htable_vector = 0; 1345 | } else { 1346 | vector_end = vector_start + (users_hash_size/60); 1347 | users_htable_vector++; 1348 | } 1349 | 1350 | for (i = vector_start; i < vector_end; i++) { 1351 | spin_lock_bh(&ht_users[i].lock); 1352 | if (ht_users[i].use > 0) { 1353 | head = &ht_users[i].user; 1354 | hlist_for_each_entry_safe(user, next, head, list_node) { 1355 | if (user->tcp_count == 0 && user->udp_count == 0 && user->other_count == 0) { 1356 | user->idle++; 1357 | } 1358 | if (user->idle > 15) { 1359 | //printk(KERN_DEBUG "xt_NAT USERS CLEAN ----------------\n"); 1360 | //printk(KERN_DEBUG "xt_NAT USERS CLEAN: Entry for destroy with src ip = %pI4\n", &user->addr); 1361 | hlist_del_rcu(&user->list_node); 1362 | ht_users[i].use--; 1363 | kfree_rcu(user, rcu); 1364 | atomic64_dec(&users_active); 1365 | //printk(KERN_DEBUG "xt_NAT USERS CLEAN ----------------\n"); 1366 | } 1367 | } 1368 | } 1369 | spin_unlock_bh(&ht_users[i].lock); 1370 | } 1371 | mod_timer( &users_cleanup_timer, jiffies + msecs_to_jiffies(1000) ); 1372 | spin_unlock_bh(&users_timer_lock); 1373 | } 1374 | 1375 | void sessions_cleanup_timer_callback( unsigned long data ) 1376 | { 1377 | struct nat_htable_ent *session; 1378 | struct hlist_head *head; 1379 | struct hlist_node *next; 1380 | unsigned int i; 1381 | void *p; 1382 | u_int32_t vector_start, vector_end; 1383 | 1384 | spin_lock_bh(&sessions_timer_lock); 1385 | 1386 | //printk( "xt_NAT TIMER CLEAN: called at (%ld)\n", jiffies ); 1387 | 1388 | if (ht_inner == NULL || ht_outer == NULL) { 1389 | printk(KERN_WARNING "xt_NAT SESSIONS CLEAN ERROR: Found null ptr for ht_inner/ht_outer\n"); 1390 | spin_unlock_bh(&sessions_timer_lock); 1391 | return; 1392 | } 1393 | 1394 | vector_start = nat_htable_vector * (nat_hash_size/100); 1395 | if (nat_htable_vector == 100) { 1396 | vector_end = nat_hash_size; 1397 | nat_htable_vector = 0; 1398 | } else { 1399 | vector_end = vector_start + (nat_hash_size/100); 1400 | nat_htable_vector++; 1401 | } 1402 | 1403 | for (i = vector_start; i < vector_end; i++) { 1404 | spin_lock_bh(&ht_inner[i].lock); 1405 | if (ht_inner[i].use > 0) { 1406 | head = &ht_inner[i].session; 1407 | hlist_for_each_entry_safe(session, next, head, list_node) { 1408 | session->data->timeout -= 10; 1409 | if (session->data->timeout == 0) { 1410 | netflow_export_flow_v5(session->proto, session->addr, session->port, get_nat_addr(session->addr), session->data->out_port, 1); 1411 | } else if (session->data->timeout <= -10) { 1412 | hlist_del_rcu(&session->list_node); 1413 | ht_inner[i].use--; 1414 | kfree_rcu(session, rcu); 1415 | update_user_limits(session->proto, session->addr, -1); 1416 | } 1417 | } 1418 | } 1419 | spin_unlock_bh(&ht_inner[i].lock); 1420 | } 1421 | 1422 | for (i = vector_start; i < vector_end; i++) { 1423 | spin_lock_bh(&ht_outer[i].lock); 1424 | if (ht_outer[i].use > 0) { 1425 | head = &ht_outer[i].session; 1426 | hlist_for_each_entry_safe(session, next, head, list_node) { 1427 | if (session->data->timeout <= -10) { 1428 | hlist_del_rcu(&session->list_node); 1429 | ht_outer[i].use--; 1430 | p = session->data; 1431 | kfree_rcu(session, rcu); 1432 | kfree(p); 1433 | atomic64_dec(&sessions_active); 1434 | } 1435 | } 1436 | } 1437 | spin_unlock_bh(&ht_outer[i].lock); 1438 | } 1439 | 1440 | mod_timer( &sessions_cleanup_timer, jiffies + msecs_to_jiffies(100) ); 1441 | spin_unlock_bh(&sessions_timer_lock); 1442 | } 1443 | 1444 | void nf_send_timer_callback( unsigned long data ) 1445 | { 1446 | spin_lock_bh(&nfsend_lock); 1447 | //printk(KERN_DEBUG "xt_NAT TIMER: Exporting netflow by timer\n"); 1448 | netflow_export_pdu_v5(); 1449 | mod_timer( &nf_send_timer, jiffies + msecs_to_jiffies(1000) ); 1450 | spin_unlock_bh(&nfsend_lock); 1451 | } 1452 | 1453 | static int nat_seq_show(struct seq_file *m, void *v) 1454 | { 1455 | struct nat_htable_ent *session; 1456 | struct hlist_head *head; 1457 | unsigned int i, count; 1458 | 1459 | count=0; 1460 | 1461 | seq_printf(m, "Proto SrcIP:SrcPort -> NatIP:NatPort\n"); 1462 | for (i = 0; i < nat_hash_size; i++) { 1463 | rcu_read_lock_bh(); 1464 | if (ht_outer[i].use > 0) { 1465 | head = &ht_outer[i].session; 1466 | hlist_for_each_entry_rcu(session, head, list_node) { 1467 | if (session->data->timeout > 0) { 1468 | seq_printf(m, "%d %pI4:%u -> %pI4:%u --- ttl: %d\n", 1469 | session->proto, 1470 | &session->data->in_addr, ntohs(session->data->in_port), 1471 | &session->addr, ntohs(session->port), 1472 | session->data->timeout); 1473 | } else { 1474 | seq_printf(m, "%d %pI4:%u -> %pI4:%u --- (will be removed due timeout)\n", 1475 | session->proto, 1476 | &session->data->in_addr, ntohs(session->data->in_port), 1477 | &session->addr, ntohs(session->port)); 1478 | } 1479 | count++; 1480 | } 1481 | } 1482 | rcu_read_unlock_bh(); 1483 | } 1484 | 1485 | seq_printf(m, "Total translations: %d\n", count); 1486 | 1487 | return 0; 1488 | } 1489 | static int nat_seq_open(struct inode *inode, struct file *file) 1490 | { 1491 | return single_open(file, nat_seq_show, NULL); 1492 | } 1493 | static const struct file_operations nat_seq_fops = { 1494 | .open = nat_seq_open, 1495 | .read = seq_read, 1496 | .llseek = seq_lseek, 1497 | .release = single_release, 1498 | }; 1499 | 1500 | 1501 | static int users_seq_show(struct seq_file *m, void *v) 1502 | { 1503 | struct user_htable_ent *user; 1504 | struct hlist_head *head; 1505 | u_int32_t nataddr; 1506 | unsigned int i, count; 1507 | 1508 | count=0; 1509 | 1510 | for (i = 0; i < users_hash_size; i++) { 1511 | rcu_read_lock_bh(); 1512 | if (ht_users[i].use > 0) { 1513 | head = &ht_users[i].user; 1514 | hlist_for_each_entry_rcu(user, head, list_node) { 1515 | if (user->idle < 15) { 1516 | nataddr = get_nat_addr(user->addr); 1517 | seq_printf(m, "%pI4 -> %pI4 (tcp: %u, udp: %u, other: %u)\n", 1518 | &user->addr, 1519 | &nataddr, 1520 | user->tcp_count, 1521 | user->udp_count, 1522 | user->other_count); 1523 | count++; 1524 | } 1525 | } 1526 | } 1527 | rcu_read_unlock_bh(); 1528 | } 1529 | 1530 | seq_printf(m, "Total users: %d\n", count); 1531 | 1532 | return 0; 1533 | } 1534 | static int users_seq_open(struct inode *inode, struct file *file) 1535 | { 1536 | return single_open(file, users_seq_show, NULL); 1537 | } 1538 | static const struct file_operations users_seq_fops = { 1539 | .open = users_seq_open, 1540 | .read = seq_read, 1541 | .llseek = seq_lseek, 1542 | .release = single_release, 1543 | }; 1544 | 1545 | static int stat_seq_show(struct seq_file *m, void *v) 1546 | { 1547 | seq_printf(m, "Active NAT sessions: %ld\n", atomic64_read(&sessions_active)); 1548 | seq_printf(m, "Tried NAT sessions: %ld\n", atomic64_read(&sessions_tried)); 1549 | seq_printf(m, "Created NAT sessions: %ld\n", atomic64_read(&sessions_created)); 1550 | seq_printf(m, "DNAT dropped pkts: %ld\n", atomic64_read(&dnat_dropped)); 1551 | seq_printf(m, "Fragmented pkts: %ld\n", atomic64_read(&frags)); 1552 | seq_printf(m, "Related ICMP pkts: %ld\n", atomic64_read(&related_icmp)); 1553 | seq_printf(m, "Active Users: %ld\n", atomic64_read(&users_active)); 1554 | 1555 | return 0; 1556 | } 1557 | static int stat_seq_open(struct inode *inode, struct file *file) 1558 | { 1559 | return single_open(file, stat_seq_show, NULL); 1560 | } 1561 | static const struct file_operations stat_seq_fops = { 1562 | .open = stat_seq_open, 1563 | .read = seq_read, 1564 | .llseek = seq_lseek, 1565 | .release = single_release, 1566 | }; 1567 | 1568 | #define SEPARATORS " ,;\t\n" 1569 | static int add_nf_destinations(const char *ptr) 1570 | { 1571 | int len; 1572 | 1573 | for (; ptr; ptr += len) { 1574 | struct sockaddr_storage ss; 1575 | struct netflow_sock *usock; 1576 | struct sockaddr_in *sin; 1577 | const char *end; 1578 | int succ = 0; 1579 | 1580 | /* skip initial separators */ 1581 | ptr += strspn(ptr, SEPARATORS); 1582 | 1583 | len = strcspn(ptr, SEPARATORS); 1584 | if (!len) 1585 | break; 1586 | memset(&ss, 0, sizeof(ss)); 1587 | 1588 | sin = (struct sockaddr_in *)&ss; 1589 | 1590 | sin->sin_family = AF_INET; 1591 | sin->sin_port = htons(2055); 1592 | succ = in4_pton(ptr, len, (u8 *)&sin->sin_addr, -1, &end); 1593 | if (succ && *end == ':') 1594 | sin->sin_port = htons(simple_strtoul(++end, NULL, 0)); 1595 | 1596 | if (!succ) { 1597 | printk(KERN_ERR "xt_NAT: can't parse netflow destination: %.*s\n", 1598 | len, ptr); 1599 | continue; 1600 | } 1601 | 1602 | if (!(usock = vmalloc(sizeof(*usock)))) { 1603 | printk(KERN_ERR "xt_NAT: can't vmalloc socket\n"); 1604 | return -ENOMEM; 1605 | } 1606 | memset(usock, 0, sizeof(*usock)); 1607 | usock->addr = ss; 1608 | list_add_tail(&usock->list, &usock_list); 1609 | printk(KERN_INFO "xt_NAT NEL: add destination %s\n", print_sockaddr(&usock->addr)); 1610 | } 1611 | return 0; 1612 | } 1613 | 1614 | static struct xt_target nat_tg_reg __read_mostly = { 1615 | .name = "NAT", 1616 | .revision = 0, 1617 | .family = NFPROTO_IPV4, 1618 | .hooks = (1 << NF_INET_FORWARD) | (1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_POST_ROUTING), 1619 | .target = nat_tg, 1620 | .targetsize = sizeof(struct xt_nat_tginfo), 1621 | .me = THIS_MODULE, 1622 | }; 1623 | 1624 | static int __init nat_tg_init(void) 1625 | { 1626 | char buff[128] = { 0 }; 1627 | int i, j; 1628 | 1629 | printk(KERN_INFO "Module xt_NAT loaded\n"); 1630 | 1631 | for(i=0, j=0; i<128 && nat_pool[i] != '-' && nat_pool[i] != '\0'; i++, j++) { 1632 | buff[j] = nat_pool[i]; 1633 | } 1634 | nat_pool_start = in_aton(buff); 1635 | 1636 | for(i++, j=0; i<128 && nat_pool[i] != '-' && nat_pool[i] != '\0'; i++, j++) { 1637 | buff[j] = nat_pool[i]; 1638 | } 1639 | nat_pool_end = in_aton(buff); 1640 | 1641 | if (nat_pool_start && nat_pool_end && nat_pool_start <= nat_pool_end ) { 1642 | printk(KERN_INFO "xt_NAT DEBUG: IP Pool from %pI4 to %pI4\n", &nat_pool_start, &nat_pool_end); 1643 | pool_table_create(); 1644 | } else { 1645 | printk(KERN_INFO "xt_NAT DEBUG: BAD IP Pool from %pI4 to %pI4\n", &nat_pool_start, &nat_pool_end); 1646 | return -1; 1647 | } 1648 | 1649 | printk(KERN_INFO "xt_NAT DEBUG: NAT hash size: %d\n", nat_hash_size); 1650 | printk(KERN_INFO "xt_NAT DEBUG: Users hash size: %d\n", users_hash_size); 1651 | 1652 | nat_htable_create(); 1653 | users_htable_create(); 1654 | pool_table_create(); 1655 | 1656 | add_nf_destinations(nf_dest); 1657 | 1658 | proc_net_nat = proc_mkdir("NAT",init_net.proc_net); 1659 | proc_create("sessions", 0644, proc_net_nat, &nat_seq_fops); 1660 | proc_create("users", 0644, proc_net_nat, &users_seq_fops); 1661 | proc_create("statistics", 0644, proc_net_nat, &stat_seq_fops); 1662 | 1663 | spin_lock_bh(&sessions_timer_lock); 1664 | setup_timer( &sessions_cleanup_timer, sessions_cleanup_timer_callback, 0 ); 1665 | mod_timer( &sessions_cleanup_timer, jiffies + msecs_to_jiffies(10 * 1000) ); 1666 | spin_unlock_bh(&sessions_timer_lock); 1667 | 1668 | spin_lock_bh(&users_timer_lock); 1669 | setup_timer( &users_cleanup_timer, users_cleanup_timer_callback, 0 ); 1670 | mod_timer( &users_cleanup_timer, jiffies + msecs_to_jiffies(60 * 1000) ); 1671 | spin_unlock_bh(&users_timer_lock); 1672 | 1673 | spin_lock_bh(&nfsend_lock); 1674 | setup_timer( &nf_send_timer, nf_send_timer_callback, 0 ); 1675 | mod_timer( &nf_send_timer, jiffies + msecs_to_jiffies(1000) ); 1676 | spin_unlock_bh(&nfsend_lock); 1677 | 1678 | return xt_register_target(&nat_tg_reg); 1679 | } 1680 | 1681 | static void __exit nat_tg_exit(void) 1682 | { 1683 | xt_unregister_target(&nat_tg_reg); 1684 | 1685 | spin_lock_bh(&sessions_timer_lock); 1686 | spin_lock_bh(&users_timer_lock); 1687 | spin_lock_bh(&nfsend_lock); 1688 | del_timer( &sessions_cleanup_timer ); 1689 | del_timer( &users_cleanup_timer ); 1690 | del_timer( &nf_send_timer ); 1691 | 1692 | remove_proc_entry( "sessions", proc_net_nat ); 1693 | remove_proc_entry( "users", proc_net_nat ); 1694 | remove_proc_entry( "statistics", proc_net_nat ); 1695 | proc_remove(proc_net_nat); 1696 | 1697 | pool_table_remove(); 1698 | users_htable_remove(); 1699 | nat_htable_remove(); 1700 | 1701 | while (!list_empty(&usock_list)) { 1702 | struct netflow_sock *usock; 1703 | 1704 | usock = list_entry(usock_list.next, struct netflow_sock, list); 1705 | list_del(&usock->list); 1706 | if (usock->sock) 1707 | sock_release(usock->sock); 1708 | usock->sock = NULL; 1709 | vfree(usock); 1710 | } 1711 | 1712 | spin_unlock_bh(&sessions_timer_lock); 1713 | spin_unlock_bh(&users_timer_lock); 1714 | spin_unlock_bh(&nfsend_lock); 1715 | 1716 | printk(KERN_INFO "Module xt_NAT unloaded\n"); 1717 | } 1718 | 1719 | module_init(nat_tg_init); 1720 | module_exit(nat_tg_exit); 1721 | 1722 | MODULE_DESCRIPTION("Xtables: Full Cone NAT"); 1723 | MODULE_AUTHOR("Andrei Sharaev "); 1724 | MODULE_LICENSE("GPL"); 1725 | MODULE_ALIAS("ipt_NAT"); 1726 | -------------------------------------------------------------------------------- /xt_NAT.h: -------------------------------------------------------------------------------- 1 | #ifndef _LINUX_NETFILTER_XT_NAT_H 2 | #define _LINUX_NETFILTER_XT_NAT_H 1 3 | 4 | enum xt_nat_target_variant { 5 | XTNAT_SNAT, 6 | XTNAT_DNAT, 7 | }; 8 | 9 | struct xt_nat_tginfo { 10 | uint8_t variant; 11 | }; 12 | 13 | #define NETFLOW5_RECORDS_MAX 30 14 | 15 | struct netflow5_record { 16 | __be32 s_addr; 17 | __be32 d_addr; 18 | __be32 nexthop; 19 | __be16 i_ifc; 20 | __be16 o_ifc; 21 | __be32 nr_packets; 22 | __be32 nr_octets; 23 | __be32 first_ms; 24 | __be32 last_ms; 25 | __be16 s_port; 26 | __be16 d_port; 27 | __u8 reserved; 28 | __u8 tcp_flags; 29 | __u8 protocol; 30 | __u8 tos; 31 | __be16 s_as; 32 | __be16 d_as; 33 | __u8 s_mask; 34 | __u8 d_mask; 35 | __u16 padding; 36 | } __attribute__ ((packed)); 37 | 38 | /* NetFlow v5 packet */ 39 | struct netflow5_pdu { 40 | __be16 version; 41 | __be16 nr_records; 42 | __be32 ts_uptime; /* ms */ 43 | __be32 ts_usecs; /* s */ 44 | __be32 ts_unsecs; /* ns */ 45 | __be32 seq; 46 | __u8 eng_type; 47 | __u8 eng_id; 48 | __u16 sampling; 49 | struct netflow5_record flow[NETFLOW5_RECORDS_MAX]; 50 | } __attribute__ ((packed)); 51 | 52 | #define NETFLOW5_HEADER_SIZE (sizeof(struct netflow5_pdu) - NETFLOW5_RECORDS_MAX * sizeof(struct netflow5_record)) 53 | 54 | #endif /* _LINUX_NETFILTER_XT_NAT_H */ 55 | 56 | --------------------------------------------------------------------------------