├── .gitignore ├── COPYING ├── Makefile ├── README.md ├── contrib └── install.sh ├── dkms.conf ├── eoipcr.c ├── kernel-patch ├── kernel-3.15.0-eoip-buildconf.patch ├── kernel-3.15.0-eoip-gre-demux.patch ├── kernel-3.15.0-eoip.patch ├── kernel-3.16.0-eoip-buildconf.patch ├── kernel-3.16.0-eoip-gre-demux.patch ├── kernel-3.16.0-eoip.patch ├── kernel-3.2.44-eoip-buildconf.patch ├── kernel-3.2.44-eoip-gre-demux.patch ├── kernel-3.2.44-eoip.patch ├── kernel-4.15.0-eoip-buildconf.patch ├── kernel-4.15.0-eoip-gre-demux.patch ├── kernel-4.15.0-eoip.patch ├── kernel-4.19.0-eoip-buildconf.patch ├── kernel-4.19.0-eoip-gre-demux.patch ├── kernel-4.19.0-eoip.patch ├── kernel-4.9.0-eoip-buildconf.patch ├── kernel-4.9.0-eoip-gre-demux.patch ├── kernel-4.9.0-eoip.patch ├── kernel-5.17.0-eoip-buildconf.patch ├── kernel-5.17.0-eoip-gre-demux.patch ├── kernel-5.17.0-eoip.patch ├── kernel-5.6.0-eoip-buildconf.patch ├── kernel-5.6.0-eoip-gre-demux.patch ├── kernel-5.6.0-eoip.patch ├── kernel-6.0.0-eoip-buildconf.patch ├── kernel-6.0.0-eoip-gre-demux.patch ├── kernel-6.0.0-eoip.patch ├── kernel-6.1.0-eoip-buildconf.patch ├── kernel-6.1.0-eoip-gre-demux.patch ├── kernel-6.1.0-eoip.patch ├── kernel-6.12.0-eoip-buildconf.patch ├── kernel-6.12.0-eoip-gre-demux.patch ├── kernel-6.12.0-eoip.patch ├── kernel-6.6.0-eoip-buildconf.patch ├── kernel-6.6.0-eoip-gre-demux.patch ├── kernel-6.6.0-eoip.patch ├── kernel-6.8.0-eoip-buildconf.patch ├── kernel-6.8.0-eoip-gre-demux.patch └── kernel-6.8.0-eoip.patch ├── libnetlink.c ├── libnetlink.h ├── out-of-tree-3.16.x ├── Makefile ├── gre-3.16.0.h └── gre_demux-3.16.0.c ├── out-of-tree-3.2.x ├── Makefile ├── gre-3.2.44.c └── gre-3.2.44.h ├── out-of-tree-4.15.x ├── Makefile ├── gre-4.15.0.h └── gre_demux-4.15.0.c ├── out-of-tree-4.19.x ├── Makefile ├── gre-4.19.0.h └── gre_demux-4.19.0.c ├── out-of-tree-4.9.x ├── Makefile ├── gre-4.9.0.h └── gre_demux-4.9.0.c ├── out-of-tree-5.10.x ├── out-of-tree-5.14.x ├── Makefile ├── gre-5.14.0.h └── gre_demux-5.14.0.c ├── out-of-tree-5.17.x ├── Makefile ├── gre-5.17.0.h └── gre_demux-5.17.0.c ├── out-of-tree-5.19.x ├── out-of-tree-5.4.x ├── out-of-tree-5.6.x ├── Makefile ├── gre-5.6.0.h └── gre_demux-5.6.0.c ├── out-of-tree-5.7.x ├── out-of-tree-6.0.x ├── Makefile ├── gre-6.0.0.h └── gre_demux-6.0.0.c ├── out-of-tree-6.1.x ├── Makefile ├── gre-6.1.0.h └── gre_demux-6.1.0.c ├── out-of-tree-6.12.x ├── Makefile ├── gre-6.12.0.h └── gre_demux-6.12.0.c ├── out-of-tree-6.4.x ├── out-of-tree-6.6.x ├── out-of-tree-6.8.x ├── Makefile ├── gre-6.8.0.h └── gre_demux-6.8.0.c ├── version.h └── version.sh /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | eoip 3 | out-of-tree-*/*o.cmd 4 | out-of-tree-*/*d 5 | out-of-tree-*/Module.symvers 6 | out-of-tree-*/modules.order 7 | out-of-tree-*/*.orig 8 | out-of-tree-*/eoip.c 9 | out-of-tree-*/*.ko 10 | out-of-tree-*/gre_demux.c 11 | out-of-tree-*/*.mod.c 12 | out-of-tree-*/gre.c 13 | out-of-tree-*/gre.h 14 | out-of-tree-*/built-in.a 15 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 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 | # use this to disable flto optimizations: 2 | # make NO_FLTO=1 3 | # and this to enable verbose mode: 4 | # make V=1 5 | 6 | TARGET=eoip 7 | 8 | ifndef NO_FLTO 9 | CFLAGS?=-O3 -fno-stack-protector -flto 10 | LDFLAGS+=-O3 -fno-stack-protector -flto 11 | else 12 | CFLAGS?=-O3 -fno-stack-protector 13 | endif 14 | 15 | KVER = $(shell uname -r) 16 | KMAJ = $(shell echo $(KVER) | \ 17 | sed -e 's/^\([0-9][0-9]*\)\.[0-9][0-9]*\.[0-9][0-9]*.*/\1/') 18 | KMIN = $(shell echo $(KVER) | \ 19 | sed -e 's/^[0-9][0-9]*\.\([0-9][0-9]*\)\.[0-9][0-9]*.*/\1/') 20 | 21 | STRIP?=strip 22 | PREFIX?=$(DESTDIR)/ 23 | 24 | MYCFLAGS:=$(CPPFLAGS) $(CFLAGS) -std=gnu90 -Wall -Wextra 25 | MYLDFLAGS=$(LDFLAGS) 26 | 27 | ifeq ("$(V)","1") 28 | Q:= 29 | E:=@true 30 | else 31 | Q:=@ 32 | E:=@echo 33 | endif 34 | 35 | all: $(TARGET) 36 | 37 | eoip: eoipcr.o libnetlink.o 38 | $(E) LD $@ 39 | $(Q)$(CC) -o $@ $^ $(MYLDFLAGS) 40 | 41 | libnetlink.o: libnetlink.c libnetlink.h 42 | $(E) CC $@ 43 | $(Q)$(CC) $(MYCFLAGS) -c -o $@ $< 44 | 45 | eoipcr.o: eoipcr.c libnetlink.h version.h 46 | $(E) CC $@ 47 | $(Q)$(CC) $(MYCFLAGS) -c -o $@ $< 48 | 49 | install: $(TARGET) 50 | $(E) STRIP $(TARGET) 51 | $(Q)$(STRIP) $(TARGET) 52 | $(E) INSTALL $(TARGET) 53 | $(Q)install -TD -m 0755 $(TARGET) $(PREFIX)sbin/$(TARGET) 54 | 55 | uninstall: 56 | $(E) UNINSTALL $(TARGET) 57 | $(Q)rm $(PREFIX)sbin/$(TARGET) 58 | 59 | clean: 60 | rm -f eoip eoipcr.o libnetlink.o 61 | 62 | modules: gre.ko eoip.ko 63 | 64 | eoip.ko: gre.ko 65 | cp out-of-tree-$(KMAJ).$(KMIN).x/eoip.ko . 66 | 67 | gre.ko: 68 | $(MAKE) -C out-of-tree-$(KMAJ).$(KMIN).x 69 | cp out-of-tree-$(KMAJ).$(KMIN).x/gre.ko . 70 | 71 | mclean: 72 | cd out-of-tree-$(KMAJ).$(KMIN).x && make clean 73 | rm -f eoip.ko 74 | rm -f gre.ko 75 | 76 | minstall: 77 | $(MAKE) -C out-of-tree-$(KMAJ).$(KMIN).x modules_install 78 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | EOIP 2 | ==== 3 | 4 | Kernel mode EOIP (Ethernet Over IP) tunnel compatible with MikroTik RouterOS 5 | 6 | There are several projects doing the same job with userland utilities via tap interfaces and raw sockets. While a userland application is easier to install and maintain it lacks the performance and stability of an in-kernel module. Especially for the simple job of adding and stripping the EOIP tunneling headers. The userland tunneling application may be good for testing, research or concept proof projects but not suitable for production environments with high bandwidth requirements. 7 | 8 | This project's goals are: 9 | 10 | - to solve the performance issue with EOIP on Linux 11 | - to make EOIP tunneling support a standard part of the Linux world 12 | 13 | Install 14 | ------- 15 | 16 | This code was developed on a 3.2.44 linux kernel and tested on the next 3.2.x releases. Patches and out-of-tree builds are provided for 3.2/3.16/4.19 kernels. It should not be hard to adapt it to different Linux kernels. 17 | 18 | - To patch a kernel tree: 19 | 20 | ````shell 21 | cd path-to-kernel-source/linux-X.Y.Z 22 | patch -p1 < path-to-eoip/kernel-patch/kernel-X.Y.Z-eoip-gre-demux.patch 23 | patch -p1 < path-to-eoip/kernel-patch/kernel-X.Y.Z-eoip-buildconf.patch 24 | patch -p1 < path-to-eoip/kernel-patch/kernel-X.Y.Z-eoip.patch 25 | ```` 26 | 27 | afterwards configure the kernel in the usual ways `make (menu/x/...)config` and do not forget to select `IP: EOIP tunnels over IP` located under `Networking options` from `Networking support` 28 | 29 | EOIP tunnel depends on `IP: GRE demultiplexer` - if it not selected then EOIP tunnel is not shown at all 30 | 31 | Unless the target is a limited embedded system, it is recommended to build EOIP and GRE demux as modules. 32 | 33 | - To build the modules out of the kernel tree: 34 | 35 | ````shell 36 | cd path-to-eoip/out-of-tree-X.Y.Z 37 | make 38 | make install 39 | ```` 40 | 41 | For this to work at least the running kernel's headers should be available. 42 | 43 | On Debian/Ubuntu systems this build process will place the newly built modules in `/lib/modules/x.x.x.x/misc`. Note that there will be two versions of `gre.ko` (the GRE demux). 44 | At least on 3.2/3.16/4.19 it is safe to replace the original version with the modified one because it is backwards compatible. 45 | 46 | The `eoip.ko` module cannot operate properly without the newly built version of GRE demux (`gre.ko`). If the original `gre.ko` is loaded then it should be removed and the newly built `gre.ko` loaded before loading `eoip.ko`. 47 | 48 | - To build the userland management utility `eoip`: 49 | 50 | ````shell 51 | cd path-to-eoip 52 | make 53 | ```` 54 | 55 | ### Example how to build out of tree 56 | 57 | This example may be used as a checklist for an out of tree build: 58 | 59 | ````shell 60 | root@ubuntu-18_04:~/eoip# make 61 | cc -Wall -Os -c libnetlink.c 62 | cc -Wall -Os -o eoip eoipcr.c libnetlink.o 63 | strip eoip 64 | root@ubuntu-18_04:~/eoip# cd out-of-tree-4.15.x/ 65 | root@ubuntu-18_04:~/eoip/out-of-tree-4.15.x# make 66 | patching file eoip.c 67 | using 4.15.0 version of gre_demux.c 68 | found running kernel version of gre.h 69 | patching file gre.h 70 | Hunk #1 succeeded at 24 (offset 15 lines). 71 | patching file gre_demux.c 72 | Hunk #3 succeeded at 137 (offset -9 lines). 73 | Hunk #4 succeeded at 173 (offset -9 lines). 74 | make[1]: Entering directory '/usr/src/linux-headers-4.15.0-106-generic' 75 | CC [M] /root/eoip/out-of-tree-4.15.x/eoip.o 76 | CC [M] /root/eoip/out-of-tree-4.15.x/gre.o 77 | Building modules, stage 2. 78 | MODPOST 2 modules 79 | CC /root/eoip/out-of-tree-4.15.x/eoip.mod.o 80 | LD [M] /root/eoip/out-of-tree-4.15.x/eoip.ko 81 | CC /root/eoip/out-of-tree-4.15.x/gre.mod.o 82 | LD [M] /root/eoip/out-of-tree-4.15.x/gre.ko 83 | make[1]: Leaving directory '/usr/src/linux-headers-4.15.0-106-generic' 84 | root@ubuntu-18_04:~/eoip/out-of-tree-4.15.x# insmod ./gre.ko 85 | root@ubuntu-18_04:~/eoip/out-of-tree-4.15.x# insmod ./eoip.ko 86 | root@ubuntu-18_04:~/eoip/out-of-tree-4.15.x# ../eoip add name eoip0 local 203.0.113.113 remote 198.51.100.100 tunnel-id 8421 87 | root@ubuntu-18_04:~/eoip/out-of-tree-4.15.x# ip li set eoip0 up 88 | ```` 89 | 90 | ### DKMS 91 | 92 | ````shell 93 | cd path-to-eoip 94 | ln -s $(pwd) /usr/src/eoip-1.1 95 | dkms add eoip/1.1 96 | dkms build eoip/1.1 97 | dkms install eoip/1.1 98 | ```` 99 | 100 | Userland management utility 101 | --------------------------- 102 | 103 | ### `eoip` - tunnel management utility 104 | 105 | ### Important notes 106 | 107 | - Normally EoIP tunnels in MikroTiks work well by only specifying the remote IP address. This code requires to configure both ends in a symmetrical way - each end of the tunnel should have the local IP address configured and equal to the remote IP address configured on the other end. 108 | - This code does not support the keepalive option; configure the tunnel on MikroTik's end with `!keepalive`. 109 | - It is a good idea to use IP fragmentation and to set MTU on both ends to 1500; using `clamp-tcp-mss` is pointless in this case. For performance it would be best if the transport network's MTU is 42+tunnel MTU (42 bytes is the EoIP protocol overhead) but obviously that is not the case over the Internet. 110 | - The EoIP protocol is connection-less and requires both ends to be able to reach the other end. In case only one end has a public IP, the other end may establish a private network by using another protocol that works over NAT (e.g. `PPTP`, `L2TP`, etc.) and run EoIP on top of the newly established private network. 111 | - Security warning: EoIP is a simple encapsulation and does implement any transport security. 112 | 113 | ### Usage 114 | 115 | - to create new eoip tunnel interface: 116 | 117 | ````none 118 | eoip add tunnel-id [name ] 119 | [local ] [remote ] 120 | [link ] [ttl ] [tos ] 121 | ```` 122 | 123 | - to change existing eoip tunnel interface: 124 | 125 | ````none 126 | eoip change name tunnel-id 127 | [local ] [remote ] 128 | [link ] [ttl ] [tos ] 129 | ```` 130 | 131 | - to list existing eoip tunnels: 132 | 133 | ````none 134 | eoip list 135 | ```` 136 | 137 | ### Example how to configure 138 | 139 | To configure an Ethernet tunnel between a MikroTik with IP 198.51.100.11 and a Linux box with IP 203.0.113.50 with tunnel id 1234: 140 | 141 | On MikroTik: 142 | 143 | `/interface eoip add clamp-tcp-mss=no !keepalive local-address=198.51.100.11 remote-address=203.0.113.50 tunnel-id=1234 mtu=1500 name=eoip1234` 144 | 145 | On Linux: 146 | 147 | `eoip add name eoip1234 local 203.0.113.50 remote 198.51.100.11 tunnel-id 1234` 148 | 149 | Installation Script 150 | ------- 151 | 152 | Example provided in contrib/install.sh 153 | 154 | 155 | Roadmap 156 | ------- 157 | 158 | - ~~make a patch for iproute2 to include eoip support~~ 159 | - ~~work towards making this code good enough for inclusion in official kernel/iproute2 releases~~ 160 | 161 | The inclusion of a reverse-engineered proprietary protocol which violates GRE standards is not going to happen in the official Linux kernel. Creating a patch for iproute2 is pointless as it would require patching and replacing one more component that in turn would make supporting a Linux system with kernel mode EoIP even harder. Thus using the included simple tool would be easier and preferred. 162 | 163 | The problem in making a stand-alone EoIP kernel module is that it requires replacing gre_demux (`gre.ko`). Linux kernel does not support overloading IP protocol handlers and EoIP does not fit anywhere in the standard gre_demux logic. A relatively sane solution might be to include the GRE demultiplexing logic in the EoIP kernel module itself, to provide a `gre` alias and to blacklist the original `gre.ko`. In this way GRE and PPTP would still be able to coexist with EoIP. 164 | 165 | - make a DKMS package 166 | - implement the `keepalive` option and probably make it the default 167 | 168 | Development process 169 | ------------------- 170 | 171 | This code was developed based on information gathered from sniffed datagrams and information from similar projects without involving any reverse engineering of code from the closed source commercial product. 172 | 173 | The protocol is not documented and although it looks like there are no deviations in the header format this cannot be guaranteed in all environments or for future releases of the commercial product. 174 | 175 | Protocol spec 176 | ------------- 177 | 178 | After the IP header (which can be fragmented, MTU 1500 is usually used for tunnels) a GRE-like datagram follows. 179 | Note that RFC 1701 is mentioned in MikroTik's docs but there is nothing in common between the standard and the actual protocol used. 180 | 181 | Header format (taken from https://github.com/katuma/eoip): 182 | 183 | ````none 184 | 0 1 2 3 185 | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 186 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 187 | | GRE FLAGS 0x20 0x01 | Protocol Type 0x6400 | = MAGIC "\x20\x01\x64\x00" 188 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 189 | | Encapsulated frame length | Tunnel ID | 190 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 191 | | Ethernet frame... | 192 | ```` 193 | 194 | Strangely enough the frame length is kept into network byte order while tunnel ID is in little endian byte order. 195 | 196 | Bugs 197 | ---- 198 | 199 | This code was tested and works without problems on quite a few different 32/64bit x86 systems. 200 | 201 | No testing was done on non-x86 and big endian hardware. 202 | 203 | There is no guarantee that there are no bugs left. Patches are welcome. 204 | 205 | License 206 | ------- 207 | 208 | All code and code modifications in this project are released under the GPL licence. Look at the COPYING file. 209 | -------------------------------------------------------------------------------- /contrib/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # exit on error 4 | set -e 5 | 6 | # Change dir to the script's location 7 | cd "$(dirname "$0")" 8 | 9 | # Check for a loaded gre module 10 | # note the cat that succeeds even if grep fails; there is set -e on top 11 | loaded=$(lsmod | grep '^gre ' | cat) 12 | if [[ "$loaded" != "" ]]; then 13 | # Show a hint of loaded modules 14 | lsmod | grep '^gre ' | cat 15 | 16 | echo "WARNING: You have a gre module loaded. Removing the existing module may break anything that requires it. Please proceed with caution." 17 | read -r -p "Proceed anyway? [y/N] " response 18 | if [[ "$response" != "y" && "$response" != "Y" ]]; then 19 | echo "Aborted by user request" 20 | exit 1 21 | fi 22 | fi 23 | 24 | # Delete the existing gre module because on some 25 | # systems depmod is not enough to override the 26 | # old gre module. 27 | find /lib/modules/ -name "gre.ko*" -delete 28 | 29 | # If called from contrib folder, change dir up 30 | basename="$(basename "$(pwd)")" 31 | if [[ "$basename" == "contrib" ]]; then 32 | cd .. 33 | fi 34 | 35 | # Build eoip tool 36 | make clean 37 | make 38 | make install 39 | 40 | # Detect Kernel Major & Minor 41 | unamer=$(uname -r) 42 | kernel=(${unamer//./ }) 43 | cd "out-of-tree-${kernel[0]}.${kernel[1]}.x" 44 | 45 | # Build eoip module 46 | make 47 | make install 48 | depmod 49 | 50 | # Show a hint of loaded modules 51 | # note the cat that succeeds even if grep fails; there is set -e on top 52 | lsmod | grep '^gre ' | cat 53 | 54 | # Remove the old module 55 | echo "Attempting to remove the gre module... if this fails, you may have a dependant module that needs to be unloaded first" 56 | rmmod gre || true 57 | 58 | # Load the new module 59 | modprobe eoip 60 | -------------------------------------------------------------------------------- /dkms.conf: -------------------------------------------------------------------------------- 1 | PACKAGE_NAME="eoip" 2 | BASEDIR=$(dirname "${BASH_SOURCE[0]}") 3 | PACKAGE_VERSION=$("$BASEDIR"/version.sh) 4 | AUTOINSTALL=yes 5 | BUILT_MODULE_NAME[0]="eoip" 6 | BUILT_MODULE_NAME[1]="gre" 7 | DEST_MODULE_LOCATION[0]="/kernel/net/ipv4" 8 | DEST_MODULE_LOCATION[1]="/updates/net/ipv4" 9 | MAKE[0]="'make' modules" 10 | STRIP[0]=no 11 | CLEAN="make mclean" 12 | -------------------------------------------------------------------------------- /eoipcr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "version.h" 11 | #include "libnetlink.h" 12 | 13 | int print_link(const struct sockaddr_nl *who __attribute((unused)), struct nlmsghdr *n, void *arg __attribute((unused))) { 14 | struct ndmsg *r = NLMSG_DATA(n); 15 | int len = n->nlmsg_len; 16 | struct rtattr *ifattr[IFLA_MAX+1]; 17 | struct rtattr *ifinfo[IFLA_INFO_MAX+1]; 18 | struct rtattr *ifgreo[IFLA_GRE_MAX+1]; 19 | const char *ifname; 20 | const char *kind; 21 | struct in_addr sip,dip; 22 | struct ifinfomsg *ifi; 23 | 24 | sip.s_addr=dip.s_addr=htonl(0); 25 | 26 | if (n->nlmsg_type != RTM_NEWLINK && n->nlmsg_type != RTM_DELLINK) { 27 | fprintf(stderr, "Not RTM_xxxLINK: %08x %08x %08x\n", n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags); 28 | return 0; 29 | } 30 | len -= NLMSG_LENGTH(sizeof(*r)); 31 | if (len < 0) { 32 | fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); 33 | return -1; 34 | } 35 | 36 | ifi=(void *)r; 37 | 38 | parse_rtattr(ifattr, IFLA_MAX, IFLA_RTA(r), n->nlmsg_len - NLMSG_LENGTH(sizeof(*r))); 39 | if (ifattr[IFLA_IFNAME]) 40 | ifname=rta_getattr_str(ifattr[IFLA_IFNAME]); 41 | else 42 | ifname=""; 43 | if (ifattr[IFLA_LINKINFO]) 44 | parse_rtattr(ifinfo, IFLA_INFO_MAX, (void *)rta_getattr_str(ifattr[IFLA_LINKINFO]), ifattr[IFLA_LINKINFO]->rta_len); 45 | else 46 | memset(ifinfo,0,sizeof ifinfo); 47 | if (ifinfo[IFLA_INFO_KIND]) 48 | kind=rta_getattr_str(ifinfo[IFLA_INFO_KIND]); 49 | else 50 | kind=""; 51 | if (!strcmp(kind,"eoip") && ifinfo[IFLA_INFO_DATA]) { 52 | char ts[IFNAMSIZ],td[IFNAMSIZ]; 53 | uint8_t ttl=0,tos=0; 54 | int tunid=0; 55 | int link=0; 56 | 57 | parse_rtattr(ifgreo, IFLA_GRE_MAX, (void *)rta_getattr_str(ifinfo[IFLA_INFO_DATA]), ifinfo[IFLA_INFO_DATA]->rta_len); 58 | if (ifgreo[IFLA_GRE_LINK]) 59 | link=rta_getattr_u32(ifgreo[IFLA_GRE_LINK]); 60 | if (ifgreo[IFLA_GRE_TOS]) 61 | tos=rta_getattr_u8(ifgreo[IFLA_GRE_TOS]); 62 | if (ifgreo[IFLA_GRE_TTL]) 63 | ttl=rta_getattr_u8(ifgreo[IFLA_GRE_TTL]); 64 | if (ifgreo[IFLA_GRE_LOCAL]) 65 | sip.s_addr=rta_getattr_u32(ifgreo[IFLA_GRE_LOCAL]); 66 | if (ifgreo[IFLA_GRE_REMOTE]) 67 | dip.s_addr=rta_getattr_u32(ifgreo[IFLA_GRE_REMOTE]); 68 | if (ifgreo[IFLA_GRE_IKEY]) 69 | tunid=rta_getattr_u32(ifgreo[IFLA_GRE_IKEY]); 70 | strcpy(ts,inet_ntoa(sip)); 71 | strcpy(td,inet_ntoa(dip)); 72 | printf("%d: %s@%d: link/%s %s remote %s tunnel-id %d ttl %d tos %d\n",ifi->ifi_index,ifname,link,kind,ts,td,tunid,ttl,tos); 73 | } 74 | 75 | return 0; 76 | } 77 | 78 | void list(void) { 79 | struct rtnl_handle rth; 80 | 81 | if (rtnl_open(&rth,0)) { 82 | perror("Cannot open rtnetlink"); 83 | return; 84 | } 85 | if (rtnl_wilddump_request(&rth, AF_UNSPEC, RTM_GETLINK) < 0) { 86 | perror("Cannot send dump request"); 87 | return; 88 | } 89 | 90 | if (rtnl_dump_filter(&rth, print_link, NULL) < 0) { 91 | fprintf(stderr, "Dump terminated\n"); 92 | return; 93 | } 94 | rtnl_close(&rth); 95 | } 96 | 97 | static int eoip_add(int excl,char *name,uint16_t tunnelid,uint32_t sip,uint32_t dip,uint32_t link,uint8_t ttl,uint8_t tos) { 98 | struct { 99 | struct nlmsghdr msg; 100 | struct ifinfomsg ifi; 101 | uint8_t buf[1024]; 102 | } req; 103 | struct rtnl_handle rth = { .fd = -1 }; 104 | struct rtattr *lnfo; 105 | struct rtattr *data; 106 | 107 | memset(&req, 0, sizeof(req)); 108 | req.msg.nlmsg_type = RTM_NEWLINK; 109 | req.msg.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); 110 | req.msg.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | (excl ? NLM_F_EXCL : 0); 111 | req.ifi.ifi_family = AF_UNSPEC; 112 | 113 | addattr_l(&req.msg, sizeof(req), IFLA_IFNAME, name, strlen(name)); 114 | lnfo = NLMSG_TAIL(&req.msg); 115 | addattr_l(&req.msg, sizeof(req), IFLA_LINKINFO, NULL, 0); 116 | addattr_l(&req.msg, sizeof(req), IFLA_INFO_KIND, "eoip", strlen("eoip")); 117 | data = NLMSG_TAIL(&req.msg); 118 | addattr_l(&req.msg, sizeof(req), IFLA_INFO_DATA, NULL, 0); 119 | 120 | addattr32(&req.msg, sizeof(req), IFLA_GRE_IKEY, tunnelid); 121 | addattr32(&req.msg, sizeof(req), IFLA_GRE_LOCAL, sip); 122 | addattr32(&req.msg, sizeof(req), IFLA_GRE_REMOTE, dip); 123 | addattr32(&req.msg, sizeof(req), IFLA_GRE_LINK, link); 124 | addattr8(&req.msg, sizeof(req), IFLA_GRE_TTL, ttl); 125 | addattr8(&req.msg, sizeof(req), IFLA_GRE_TOS, tos); 126 | 127 | data->rta_len = (void *)NLMSG_TAIL(&req.msg) - (void *)data; 128 | lnfo->rta_len = (void *)NLMSG_TAIL(&req.msg) - (void *)lnfo; 129 | 130 | 131 | if (rtnl_open(&rth, 0)) { 132 | fprintf(stderr, "cannot open netlink\n"); 133 | return -1; 134 | } 135 | 136 | if (rtnl_talk(&rth, &req.msg, 0, 0, NULL) < 0) { 137 | fprintf(stderr, "failed to talk to netlink!\n"); 138 | return -1; 139 | } 140 | 141 | rtnl_close(&rth); 142 | return 0; 143 | } 144 | 145 | typedef enum { 146 | E_AMBIGUOUS = -1, 147 | E_NONE = 0, 148 | C_LIST, 149 | C_ADD, 150 | C_SET, 151 | C_VER, 152 | C_HELP, 153 | P_LOCAL, 154 | P_REMOTE, 155 | P_TUNNELID, 156 | P_TTL, 157 | P_TOS, 158 | P_LINK, 159 | P_NAME, 160 | } e_cmd; 161 | 162 | typedef struct { 163 | char *cmd; 164 | e_cmd cid; 165 | } s_cmd; 166 | 167 | static s_cmd cmds[] = { 168 | { .cmd = "list", .cid = C_LIST, }, 169 | { .cmd = "show", .cid = C_LIST, }, 170 | { .cmd = "add", .cid = C_ADD, }, 171 | { .cmd = "new", .cid = C_ADD, }, 172 | { .cmd = "set", .cid = C_SET, }, 173 | { .cmd = "change", .cid = C_SET, }, 174 | { .cmd = "version", .cid = C_VER, }, 175 | { .cmd = "--version", .cid = C_VER, }, 176 | { .cmd = "-v", .cid = C_VER, }, 177 | { .cmd = "help", .cid = C_HELP, }, 178 | { .cmd = "--help", .cid = C_HELP, }, 179 | { .cmd = "-h", .cid = C_HELP, }, 180 | { .cmd = NULL, .cid = 0, }, 181 | }; 182 | 183 | static s_cmd prms[] = { 184 | { .cmd = "local", .cid = P_LOCAL, }, 185 | { .cmd = "remote", .cid = P_REMOTE, }, 186 | { .cmd = "tunnel-id", .cid = P_TUNNELID, }, 187 | { .cmd = "tid", .cid = P_TUNNELID, }, 188 | { .cmd = "ttl", .cid = P_TTL, }, 189 | { .cmd = "tos", .cid = P_TOS, }, 190 | { .cmd = "link", .cid = P_LINK, }, 191 | { .cmd = "name", .cid = P_NAME, }, 192 | { .cmd = NULL, .cid = 0, }, 193 | }; 194 | 195 | static e_cmd find_cmd(s_cmd *l, char *pcmd) { 196 | int cnt=0; 197 | int len=0; 198 | e_cmd match=E_NONE; 199 | 200 | while (l && pcmd && l->cmd) { 201 | char *ha = l->cmd; 202 | char *ne = pcmd; 203 | int clen = 0; 204 | 205 | while (*ha && *ne && *ha == *ne) 206 | ha++, ne++, clen++; 207 | 208 | if (!*ne) { 209 | if (clen && clen > len) { 210 | cnt = 0; 211 | len = clen; 212 | match = l->cid; 213 | } 214 | if (clen && clen == len) 215 | cnt++; 216 | } 217 | l++; 218 | } 219 | if (cnt == 1) 220 | return match; 221 | return cnt ? E_AMBIGUOUS : E_NONE; 222 | } 223 | 224 | static void version(void) { 225 | printf("eoip version %s\n",EOIP_VERSION); 226 | } 227 | 228 | static void usage(char *me) { 229 | printf("usage:\n" 230 | "\t%s add [name ] tunnel-id [local ] remote [ttl ] [tos ] [link ]\n" 231 | "\t%s set name tunnel-id [local ] remote [ttl ] [tos ] [link ]\n" 232 | "\t%s list\n" 233 | "\t%s version\n" 234 | ,me,me,me,me); 235 | } 236 | 237 | int main(int argc,char **argv) { 238 | if (argc >= 1) { 239 | e_cmd c = (argc == 1) ? C_LIST : find_cmd(cmds, argv[1]); 240 | int excl = 1; 241 | 242 | switch (c) { 243 | dafeutl: 244 | default: 245 | case C_HELP: 246 | usage(argv[0]); 247 | return 0; 248 | case C_VER: 249 | version(); 250 | return 0; 251 | case C_LIST: 252 | if (argc > 2) 253 | goto dafeutl; 254 | list(); 255 | return 0; 256 | case C_SET: 257 | excl = 0; 258 | // fall through 259 | case C_ADD: { 260 | char ifname[IFNAMSIZ + 1] = ""; 261 | uint32_t sip = htonl(0), dip = htonl(0); 262 | uint32_t tid = ~0; 263 | uint8_t ttl=0, tos=0; 264 | uint32_t link = 0; 265 | int i=2; 266 | 267 | while (i < argc) { 268 | e_cmd p = find_cmd(prms, argv[i]); 269 | int noarg=!((i + 1) < argc); 270 | struct in_addr iad; 271 | 272 | switch (p) { 273 | default: 274 | break; 275 | case E_NONE: 276 | printf("unknown option: %s\n", argv[i]); 277 | return 0; 278 | case E_AMBIGUOUS: 279 | printf("option is ambiguous: %s\n", argv[i]); 280 | return 0; 281 | } 282 | 283 | if (noarg) { 284 | printf("option: %s requires an argument\n", argv[i]); 285 | return 0; 286 | } 287 | 288 | switch (p) { 289 | default: 290 | printf("BUG!\n"); 291 | return 0; 292 | case P_NAME: 293 | ifname[(sizeof ifname)-1] = 0; 294 | strncpy(ifname,argv[i + 1], IFNAMSIZ); 295 | break; 296 | case P_TTL: 297 | ttl=atoi(argv[i + 1]); 298 | break; 299 | case P_TOS: 300 | tos=atoi(argv[i + 1]); 301 | break; 302 | case P_LINK: 303 | // convert ifname to ifinidex, also support numeric arg 304 | link=if_nametoindex(argv[i + 1]); 305 | if (!link) 306 | link=atoi(argv[i + 1]); 307 | if (!link) { 308 | printf("invalid interface name/index: %s\n", argv[i + 1]); 309 | return 0; 310 | } 311 | break; 312 | case P_TUNNELID: 313 | tid=atoi(argv[i + 1]); 314 | break; 315 | case P_LOCAL: 316 | if (!inet_aton(argv[i + 1], &iad)) { 317 | printf("invalid ip address: %s\n", argv[i + 1]); 318 | return 0; 319 | } 320 | sip = iad.s_addr; 321 | break; 322 | case P_REMOTE: 323 | if (!inet_aton(argv[i + 1], &iad)) { 324 | printf("invalid ip address: %s\n", argv[i + 1]); 325 | return 0; 326 | } 327 | dip = iad.s_addr; 328 | break; 329 | } 330 | i += 2; 331 | } 332 | if (tid > 0xffff) { 333 | if (tid == ~0U) 334 | printf("tunnel-id is mandatory parameter\n"); 335 | else 336 | printf("invalid tunnel-id value: %u\n",tid); 337 | return 0; 338 | } 339 | // tunnel id is in host byte order, addresses are in net byte order 340 | eoip_add(excl,ifname,tid,sip,dip,link,ttl,tos); 341 | return 0; 342 | } 343 | } 344 | } 345 | return 0; 346 | } 347 | -------------------------------------------------------------------------------- /kernel-patch/kernel-3.15.0-eoip-buildconf.patch: -------------------------------------------------------------------------------- 1 | --- linux-3.15/net/ipv4/Makefile.orig 2014-06-14 00:22:46.749706936 +0300 2 | +++ linux-3.15/net/ipv4/Makefile 2014-06-14 00:23:53.257704010 +0300 3 | @@ -23,6 +23,7 @@ gre-y := gre_demux.o 4 | obj-$(CONFIG_NET_IPGRE_DEMUX) += gre.o 5 | obj-$(CONFIG_NET_IPGRE) += ip_gre.o 6 | obj-$(CONFIG_NET_IPVTI) += ip_vti.o 7 | +obj-$(CONFIG_NET_EOIP) += eoip.o 8 | obj-$(CONFIG_SYN_COOKIES) += syncookies.o 9 | obj-$(CONFIG_INET_AH) += ah4.o 10 | obj-$(CONFIG_INET_ESP) += esp4.o 11 | --- linux-3.15/net/ipv4/Kconfig.orig 2014-06-14 00:18:28.437718301 +0300 12 | +++ linux-3.15/net/ipv4/Kconfig 2014-06-14 00:22:32.273707573 +0300 13 | @@ -182,7 +182,7 @@ config NET_IPGRE_DEMUX 14 | tristate "IP: GRE demultiplexer" 15 | help 16 | This is helper module to demultiplex GRE packets on GRE version field criteria. 17 | - Required by ip_gre and pptp modules. 18 | + Required by ip_gre, pptp and eoip modules. 19 | 20 | config NET_IP_TUNNEL 21 | tristate 22 | @@ -212,6 +212,17 @@ config NET_IPGRE_BROADCAST 23 | Network), but can be distributed all over the Internet. If you want 24 | to do that, say Y here and to "IP multicast routing" below. 25 | 26 | +config NET_EOIP 27 | + tristate "IP: EOIP ethernet tunnels over IP" 28 | + depends on (IPV6 || IPV6=n) && NET_IPGRE_DEMUX 29 | + help 30 | + Tunneling means encapsulating data of one protocol type within 31 | + another protocol and sending it over a channel that understands the 32 | + encapsulating protocol. This particular tunneling driver implements 33 | + MikroTik RouterOS compatible encapsulation of ethernet frames over 34 | + existing IPv4 infrastructure. It is useful if the other endpoint 35 | + is a MikroTik router. 36 | + 37 | config IP_MROUTE 38 | bool "IP: multicast routing" 39 | depends on IP_MULTICAST 40 | -------------------------------------------------------------------------------- /kernel-patch/kernel-3.15.0-eoip-gre-demux.patch: -------------------------------------------------------------------------------- 1 | --- linux-3.15/include/net/gre.h.orig 2014-07-04 02:52:26.955400395 +0300 2 | +++ linux-3.15/include/net/gre.h 2014-06-13 23:12:31.745892381 +0300 3 | @@ -9,6 +9,13 @@ 4 | #define GREPROTO_MAX 2 5 | #define GRE_IP_PROTO_MAX 2 6 | 7 | +/* handle protocols with non-standard GRE header by ids that do not overlap 8 | + * with possible standard GRE protocol versions (0x00 - 0x7f) 9 | + */ 10 | +#define GREPROTO_NONSTD_BASE 0x80 11 | +#define GREPROTO_NONSTD_EOIP (0 + GREPROTO_NONSTD_BASE) 12 | +#define GREPROTO_NONSTD_MAX (1 + GREPROTO_NONSTD_BASE) 13 | + 14 | struct gre_protocol { 15 | int (*handler)(struct sk_buff *skb); 16 | void (*err_handler)(struct sk_buff *skb, u32 info); 17 | --- linux-3.15/net/ipv4/gre_demux.c.orig 2014-07-04 02:53:03.975398766 +0300 18 | +++ linux-3.15/net/ipv4/gre_demux.c 2014-06-16 00:10:05.118137863 +0300 19 | @@ -30,13 +30,19 @@ 20 | #include 21 | #include 22 | 23 | -static const struct gre_protocol __rcu *gre_proto[GREPROTO_MAX] __read_mostly; 24 | +#define GREPROTO_CNT \ 25 | + (GREPROTO_MAX + GREPROTO_NONSTD_MAX - GREPROTO_NONSTD_BASE) 26 | + 27 | +static const struct gre_protocol __rcu *gre_proto[GREPROTO_CNT] __read_mostly; 28 | static struct gre_cisco_protocol __rcu *gre_cisco_proto_list[GRE_IP_PROTO_MAX]; 29 | 30 | int gre_add_protocol(const struct gre_protocol *proto, u8 version) 31 | { 32 | - if (version >= GREPROTO_MAX) 33 | - return -EINVAL; 34 | + if (version >= GREPROTO_NONSTD_BASE && version < GREPROTO_NONSTD_MAX) 35 | + version -= GREPROTO_NONSTD_BASE - GREPROTO_MAX; 36 | + else 37 | + if (version >= GREPROTO_MAX) 38 | + return -EINVAL; 39 | 40 | return (cmpxchg((const struct gre_protocol **)&gre_proto[version], NULL, proto) == NULL) ? 41 | 0 : -EBUSY; 42 | @@ -47,8 +53,11 @@ int gre_del_protocol(const struct gre_pr 43 | { 44 | int ret; 45 | 46 | - if (version >= GREPROTO_MAX) 47 | - return -EINVAL; 48 | + if (version >= GREPROTO_NONSTD_BASE && version < GREPROTO_NONSTD_MAX) 49 | + version -= GREPROTO_NONSTD_BASE - GREPROTO_MAX; 50 | + else 51 | + if (version >= GREPROTO_MAX) 52 | + return -EINVAL; 53 | 54 | ret = (cmpxchg((const struct gre_protocol **)&gre_proto[version], proto, NULL) == proto) ? 55 | 0 : -EBUSY; 56 | @@ -275,12 +284,22 @@ static int gre_rcv(struct sk_buff *skb) 57 | u8 ver; 58 | int ret; 59 | 60 | + /* the standard GRE header is 12 octets; the EOIP header is 8 61 | + * 4 octets long ethernet packet can not be valid 62 | + */ 63 | if (!pskb_may_pull(skb, 12)) 64 | goto drop; 65 | 66 | - ver = skb->data[1]&0x7f; 67 | - if (ver >= GREPROTO_MAX) 68 | - goto drop; 69 | + /* check for custom EOIP header */ 70 | + if (skb->data[0] == 0x20 && skb->data[1] == 0x01 && 71 | + skb->data[2] == 0x64 && skb->data[3] == 0x00) 72 | + ver = GREPROTO_NONSTD_EOIP - GREPROTO_NONSTD_BASE 73 | + + GREPROTO_MAX; 74 | + else { 75 | + ver = skb->data[1]&0x7f; 76 | + if (ver >= GREPROTO_MAX) 77 | + goto drop; 78 | + } 79 | 80 | rcu_read_lock(); 81 | proto = rcu_dereference(gre_proto[ver]); 82 | @@ -301,10 +320,19 @@ static void gre_err(struct sk_buff *skb, 83 | { 84 | const struct gre_protocol *proto; 85 | const struct iphdr *iph = (const struct iphdr *)skb->data; 86 | - u8 ver = skb->data[(iph->ihl<<2) + 1]&0x7f; 87 | + u8 ver; 88 | 89 | - if (ver >= GREPROTO_MAX) 90 | - return; 91 | + if (skb->data[(iph->ihl<<2) + 0] == 0x20 && 92 | + skb->data[(iph->ihl<<2) + 1] == 0x01 && 93 | + skb->data[(iph->ihl<<2) + 2] == 0x64 && 94 | + skb->data[(iph->ihl<<2) + 3] == 0x00) 95 | + ver = GREPROTO_NONSTD_EOIP - GREPROTO_NONSTD_BASE 96 | + + GREPROTO_MAX; 97 | + else { 98 | + ver = skb->data[(iph->ihl<<2) + 1]&0x7f; 99 | + if (ver >= GREPROTO_MAX) 100 | + return; 101 | + } 102 | 103 | rcu_read_lock(); 104 | proto = rcu_dereference(gre_proto[ver]); 105 | -------------------------------------------------------------------------------- /kernel-patch/kernel-3.16.0-eoip-buildconf.patch: -------------------------------------------------------------------------------- 1 | --- linux-3.15/net/ipv4/Makefile.orig 2014-06-14 00:22:46.749706936 +0300 2 | +++ linux-3.15/net/ipv4/Makefile 2014-06-14 00:23:53.257704010 +0300 3 | @@ -23,6 +23,7 @@ gre-y := gre_demux.o 4 | obj-$(CONFIG_NET_IPGRE_DEMUX) += gre.o 5 | obj-$(CONFIG_NET_IPGRE) += ip_gre.o 6 | obj-$(CONFIG_NET_IPVTI) += ip_vti.o 7 | +obj-$(CONFIG_NET_EOIP) += eoip.o 8 | obj-$(CONFIG_SYN_COOKIES) += syncookies.o 9 | obj-$(CONFIG_INET_AH) += ah4.o 10 | obj-$(CONFIG_INET_ESP) += esp4.o 11 | --- linux-3.15/net/ipv4/Kconfig.orig 2014-06-14 00:18:28.437718301 +0300 12 | +++ linux-3.15/net/ipv4/Kconfig 2014-06-14 00:22:32.273707573 +0300 13 | @@ -182,7 +182,7 @@ config NET_IPGRE_DEMUX 14 | tristate "IP: GRE demultiplexer" 15 | help 16 | This is helper module to demultiplex GRE packets on GRE version field criteria. 17 | - Required by ip_gre and pptp modules. 18 | + Required by ip_gre, pptp and eoip modules. 19 | 20 | config NET_IP_TUNNEL 21 | tristate 22 | @@ -212,6 +212,17 @@ config NET_IPGRE_BROADCAST 23 | Network), but can be distributed all over the Internet. If you want 24 | to do that, say Y here and to "IP multicast routing" below. 25 | 26 | +config NET_EOIP 27 | + tristate "IP: EOIP ethernet tunnels over IP" 28 | + depends on (IPV6 || IPV6=n) && NET_IPGRE_DEMUX 29 | + help 30 | + Tunneling means encapsulating data of one protocol type within 31 | + another protocol and sending it over a channel that understands the 32 | + encapsulating protocol. This particular tunneling driver implements 33 | + MikroTik RouterOS compatible encapsulation of ethernet frames over 34 | + existing IPv4 infrastructure. It is useful if the other endpoint 35 | + is a MikroTik router. 36 | + 37 | config IP_MROUTE 38 | bool "IP: multicast routing" 39 | depends on IP_MULTICAST 40 | -------------------------------------------------------------------------------- /kernel-patch/kernel-3.16.0-eoip-gre-demux.patch: -------------------------------------------------------------------------------- 1 | --- linux-3.15/include/net/gre.h.orig 2014-07-04 02:52:26.955400395 +0300 2 | +++ linux-3.15/include/net/gre.h 2014-06-13 23:12:31.745892381 +0300 3 | @@ -9,6 +9,13 @@ 4 | #define GREPROTO_MAX 2 5 | #define GRE_IP_PROTO_MAX 2 6 | 7 | +/* handle protocols with non-standard GRE header by ids that do not overlap 8 | + * with possible standard GRE protocol versions (0x00 - 0x7f) 9 | + */ 10 | +#define GREPROTO_NONSTD_BASE 0x80 11 | +#define GREPROTO_NONSTD_EOIP (0 + GREPROTO_NONSTD_BASE) 12 | +#define GREPROTO_NONSTD_MAX (1 + GREPROTO_NONSTD_BASE) 13 | + 14 | struct gre_protocol { 15 | int (*handler)(struct sk_buff *skb); 16 | void (*err_handler)(struct sk_buff *skb, u32 info); 17 | --- linux-3.15/net/ipv4/gre_demux.c.orig 2014-07-04 02:53:03.975398766 +0300 18 | +++ linux-3.15/net/ipv4/gre_demux.c 2014-06-16 00:10:05.118137863 +0300 19 | @@ -30,13 +30,19 @@ 20 | #include 21 | #include 22 | 23 | -static const struct gre_protocol __rcu *gre_proto[GREPROTO_MAX] __read_mostly; 24 | +#define GREPROTO_CNT \ 25 | + (GREPROTO_MAX + GREPROTO_NONSTD_MAX - GREPROTO_NONSTD_BASE) 26 | + 27 | +static const struct gre_protocol __rcu *gre_proto[GREPROTO_CNT] __read_mostly; 28 | static struct gre_cisco_protocol __rcu *gre_cisco_proto_list[GRE_IP_PROTO_MAX]; 29 | 30 | int gre_add_protocol(const struct gre_protocol *proto, u8 version) 31 | { 32 | - if (version >= GREPROTO_MAX) 33 | - return -EINVAL; 34 | + if (version >= GREPROTO_NONSTD_BASE && version < GREPROTO_NONSTD_MAX) 35 | + version -= GREPROTO_NONSTD_BASE - GREPROTO_MAX; 36 | + else 37 | + if (version >= GREPROTO_MAX) 38 | + return -EINVAL; 39 | 40 | return (cmpxchg((const struct gre_protocol **)&gre_proto[version], NULL, proto) == NULL) ? 41 | 0 : -EBUSY; 42 | @@ -47,8 +53,11 @@ int gre_del_protocol(const struct gre_pr 43 | { 44 | int ret; 45 | 46 | - if (version >= GREPROTO_MAX) 47 | - return -EINVAL; 48 | + if (version >= GREPROTO_NONSTD_BASE && version < GREPROTO_NONSTD_MAX) 49 | + version -= GREPROTO_NONSTD_BASE - GREPROTO_MAX; 50 | + else 51 | + if (version >= GREPROTO_MAX) 52 | + return -EINVAL; 53 | 54 | ret = (cmpxchg((const struct gre_protocol **)&gre_proto[version], proto, NULL) == proto) ? 55 | 0 : -EBUSY; 56 | @@ -275,12 +284,22 @@ static int gre_rcv(struct sk_buff *skb) 57 | u8 ver; 58 | int ret; 59 | 60 | + /* the standard GRE header is 12 octets; the EOIP header is 8 61 | + * 4 octets long ethernet packet can not be valid 62 | + */ 63 | if (!pskb_may_pull(skb, 12)) 64 | goto drop; 65 | 66 | - ver = skb->data[1]&0x7f; 67 | - if (ver >= GREPROTO_MAX) 68 | - goto drop; 69 | + /* check for custom EOIP header */ 70 | + if (skb->data[0] == 0x20 && skb->data[1] == 0x01 && 71 | + skb->data[2] == 0x64 && skb->data[3] == 0x00) 72 | + ver = GREPROTO_NONSTD_EOIP - GREPROTO_NONSTD_BASE 73 | + + GREPROTO_MAX; 74 | + else { 75 | + ver = skb->data[1]&0x7f; 76 | + if (ver >= GREPROTO_MAX) 77 | + goto drop; 78 | + } 79 | 80 | rcu_read_lock(); 81 | proto = rcu_dereference(gre_proto[ver]); 82 | @@ -301,10 +320,19 @@ static void gre_err(struct sk_buff *skb, 83 | { 84 | const struct gre_protocol *proto; 85 | const struct iphdr *iph = (const struct iphdr *)skb->data; 86 | - u8 ver = skb->data[(iph->ihl<<2) + 1]&0x7f; 87 | + u8 ver; 88 | 89 | - if (ver >= GREPROTO_MAX) 90 | - return; 91 | + if (skb->data[(iph->ihl<<2) + 0] == 0x20 && 92 | + skb->data[(iph->ihl<<2) + 1] == 0x01 && 93 | + skb->data[(iph->ihl<<2) + 2] == 0x64 && 94 | + skb->data[(iph->ihl<<2) + 3] == 0x00) 95 | + ver = GREPROTO_NONSTD_EOIP - GREPROTO_NONSTD_BASE 96 | + + GREPROTO_MAX; 97 | + else { 98 | + ver = skb->data[(iph->ihl<<2) + 1]&0x7f; 99 | + if (ver >= GREPROTO_MAX) 100 | + return; 101 | + } 102 | 103 | rcu_read_lock(); 104 | proto = rcu_dereference(gre_proto[ver]); 105 | -------------------------------------------------------------------------------- /kernel-patch/kernel-3.2.44-eoip-buildconf.patch: -------------------------------------------------------------------------------- 1 | 2 | Signed-off-by: Boian Bonev 3 | 4 | --- linux-3.2.44/net/ipv4/Makefile.orig 2013-05-08 20:43:50.892913537 +0300 5 | +++ linux-3.2.44/net/ipv4/Makefile 2013-05-08 20:43:59.853005836 +0300 6 | @@ -20,6 +20,7 @@ 7 | obj-$(CONFIG_NET_IPIP) += ipip.o 8 | obj-$(CONFIG_NET_IPGRE_DEMUX) += gre.o 9 | obj-$(CONFIG_NET_IPGRE) += ip_gre.o 10 | +obj-$(CONFIG_NET_EOIP) += eoip.o 11 | obj-$(CONFIG_SYN_COOKIES) += syncookies.o 12 | obj-$(CONFIG_INET_AH) += ah4.o 13 | obj-$(CONFIG_INET_ESP) += esp4.o 14 | --- linux-3.2.45/net/ipv4/Kconfig.orig 2013-05-17 03:53:09.824509164 +0300 15 | +++ linux-3.2.45/net/ipv4/Kconfig 2013-05-17 04:01:14.212510430 +0300 16 | @@ -186,7 +186,7 @@ 17 | tristate "IP: GRE demultiplexer" 18 | help 19 | This is helper module to demultiplex GRE packets on GRE version field criteria. 20 | - Required by ip_gre and pptp modules. 21 | + Required by ip_gre, pptp and eoip modules. 22 | 23 | config NET_IPGRE 24 | tristate "IP: GRE tunnels over IP" 25 | @@ -211,6 +211,17 @@ 26 | Network), but can be distributed all over the Internet. If you want 27 | to do that, say Y here and to "IP multicast routing" below. 28 | 29 | +config NET_EOIP 30 | + tristate "IP: EOIP ethernet tunnels over IP" 31 | + depends on (IPV6 || IPV6=n) && NET_IPGRE_DEMUX 32 | + help 33 | + Tunneling means encapsulating data of one protocol type within 34 | + another protocol and sending it over a channel that understands the 35 | + encapsulating protocol. This particular tunneling driver implements 36 | + MikroTik RouterOS compatible encapsulation of ethernet frames over 37 | + existing IPv4 infrastructure. It is useful if the other endpoint 38 | + is a MirkoTik router. 39 | + 40 | config IP_MROUTE 41 | bool "IP: multicast routing" 42 | depends on IP_MULTICAST 43 | -------------------------------------------------------------------------------- /kernel-patch/kernel-3.2.44-eoip-gre-demux.patch: -------------------------------------------------------------------------------- 1 | 2 | Signed-off-by: Boian Bonev 3 | 4 | --- linux-3.2.45/include/net/gre.h.orig 2013-05-17 03:22:37.204504375 +0300 5 | +++ linux-3.2.45/include/net/gre.h 2013-05-17 14:52:40.516612537 +0300 6 | @@ -7,6 +7,14 @@ 7 | #define GREPROTO_PPTP 1 8 | #define GREPROTO_MAX 2 9 | 10 | +/* handle protocols with non-standard GRE header by ids that do not overlap 11 | + * with possible standard GRE protocol versions (0x00 - 0x7f) 12 | + */ 13 | +#define GREPROTO_NONSTD_BASE 0x80 14 | +#define GREPROTO_NONSTD_EOIP (0 + GREPROTO_NONSTD_BASE) 15 | +#define GREPROTO_NONSTD_MAX (1 + GREPROTO_NONSTD_BASE) 16 | + 17 | + 18 | struct gre_protocol { 19 | int (*handler)(struct sk_buff *skb); 20 | void (*err_handler)(struct sk_buff *skb, u32 info); 21 | --- linux-3.2.45/net/ipv4/gre.c.orig 2013-05-17 03:22:22.772504339 +0300 22 | +++ linux-3.2.45/net/ipv4/gre.c 2013-05-17 14:55:28.344612975 +0300 23 | @@ -21,14 +21,19 @@ 24 | #include 25 | #include 26 | 27 | +#define GREPROTO_CNT \ 28 | + (GREPROTO_MAX + GREPROTO_NONSTD_MAX - GREPROTO_NONSTD_BASE) 29 | 30 | -static const struct gre_protocol __rcu *gre_proto[GREPROTO_MAX] __read_mostly; 31 | +static const struct gre_protocol __rcu *gre_proto[GREPROTO_CNT] __read_mostly; 32 | static DEFINE_SPINLOCK(gre_proto_lock); 33 | 34 | int gre_add_protocol(const struct gre_protocol *proto, u8 version) 35 | { 36 | - if (version >= GREPROTO_MAX) 37 | - goto err_out; 38 | + if (version >= GREPROTO_NONSTD_BASE && version < GREPROTO_NONSTD_MAX) 39 | + version -= GREPROTO_NONSTD_BASE - GREPROTO_MAX; 40 | + else 41 | + if (version >= GREPROTO_MAX) 42 | + goto err_out; 43 | 44 | spin_lock(&gre_proto_lock); 45 | if (gre_proto[version]) 46 | @@ -47,8 +52,11 @@ EXPORT_SYMBOL_GPL(gre_add_protocol); 47 | 48 | int gre_del_protocol(const struct gre_protocol *proto, u8 version) 49 | { 50 | - if (version >= GREPROTO_MAX) 51 | - goto err_out; 52 | + if (version >= GREPROTO_NONSTD_BASE && version < GREPROTO_NONSTD_MAX) 53 | + version -= GREPROTO_NONSTD_BASE - GREPROTO_MAX; 54 | + else 55 | + if (version >= GREPROTO_MAX) 56 | + goto err_out; 57 | 58 | spin_lock(&gre_proto_lock); 59 | if (rcu_dereference_protected(gre_proto[version], 60 | @@ -72,12 +80,22 @@ static int gre_rcv(struct sk_buff *skb) 61 | u8 ver; 62 | int ret; 63 | 64 | + /* the standard GRE header is 12 octets; the EOIP header is 8 65 | + * 4 octets long ethernet packet can not be valid 66 | + */ 67 | if (!pskb_may_pull(skb, 12)) 68 | goto drop; 69 | 70 | - ver = skb->data[1]&0x7f; 71 | - if (ver >= GREPROTO_MAX) 72 | - goto drop; 73 | + /* check for custom EOIP header */ 74 | + if (skb->data[0] == 0x20 && skb->data[1] == 0x01 && 75 | + skb->data[2] == 0x64 && skb->data[3] == 0x00) 76 | + ver = GREPROTO_NONSTD_EOIP - GREPROTO_NONSTD_BASE 77 | + + GREPROTO_MAX; 78 | + else { 79 | + ver = skb->data[1]&0x7f; 80 | + if (ver >= GREPROTO_MAX) 81 | + goto drop; 82 | + } 83 | 84 | rcu_read_lock(); 85 | proto = rcu_dereference(gre_proto[ver]); 86 | @@ -98,10 +116,19 @@ static void gre_err(struct sk_buff *skb, 87 | { 88 | const struct gre_protocol *proto; 89 | const struct iphdr *iph = (const struct iphdr *)skb->data; 90 | - u8 ver = skb->data[(iph->ihl<<2) + 1]&0x7f; 91 | + u8 ver; 92 | 93 | - if (ver >= GREPROTO_MAX) 94 | - return; 95 | + if (skb->data[(iph->ihl<<2) + 0] == 0x20 && 96 | + skb->data[(iph->ihl<<2) + 1] == 0x01 && 97 | + skb->data[(iph->ihl<<2) + 2] == 0x64 && 98 | + skb->data[(iph->ihl<<2) + 3] == 0x00) 99 | + ver = GREPROTO_NONSTD_EOIP - GREPROTO_NONSTD_BASE 100 | + + GREPROTO_MAX; 101 | + else { 102 | + ver = skb->data[(iph->ihl<<2) + 1]&0x7f; 103 | + if (ver >= GREPROTO_MAX) 104 | + return; 105 | + } 106 | 107 | rcu_read_lock(); 108 | proto = rcu_dereference(gre_proto[ver]); 109 | -------------------------------------------------------------------------------- /kernel-patch/kernel-4.15.0-eoip-buildconf.patch: -------------------------------------------------------------------------------- 1 | --- linux-3.15/net/ipv4/Makefile.orig 2014-06-14 00:22:46.749706936 +0300 2 | +++ linux-3.15/net/ipv4/Makefile 2014-06-14 00:23:53.257704010 +0300 3 | @@ -23,6 +23,7 @@ gre-y := gre_demux.o 4 | obj-$(CONFIG_NET_IPGRE_DEMUX) += gre.o 5 | obj-$(CONFIG_NET_IPGRE) += ip_gre.o 6 | obj-$(CONFIG_NET_IPVTI) += ip_vti.o 7 | +obj-$(CONFIG_NET_EOIP) += eoip.o 8 | obj-$(CONFIG_SYN_COOKIES) += syncookies.o 9 | obj-$(CONFIG_INET_AH) += ah4.o 10 | obj-$(CONFIG_INET_ESP) += esp4.o 11 | --- linux-3.15/net/ipv4/Kconfig.orig 2014-06-14 00:18:28.437718301 +0300 12 | +++ linux-3.15/net/ipv4/Kconfig 2014-06-14 00:22:32.273707573 +0300 13 | @@ -182,7 +182,7 @@ config NET_IPGRE_DEMUX 14 | tristate "IP: GRE demultiplexer" 15 | help 16 | This is helper module to demultiplex GRE packets on GRE version field criteria. 17 | - Required by ip_gre and pptp modules. 18 | + Required by ip_gre, pptp and eoip modules. 19 | 20 | config NET_IP_TUNNEL 21 | tristate 22 | @@ -212,6 +212,17 @@ config NET_IPGRE_BROADCAST 23 | Network), but can be distributed all over the Internet. If you want 24 | to do that, say Y here and to "IP multicast routing" below. 25 | 26 | +config NET_EOIP 27 | + tristate "IP: EOIP ethernet tunnels over IP" 28 | + depends on (IPV6 || IPV6=n) && NET_IPGRE_DEMUX 29 | + help 30 | + Tunneling means encapsulating data of one protocol type within 31 | + another protocol and sending it over a channel that understands the 32 | + encapsulating protocol. This particular tunneling driver implements 33 | + MikroTik RouterOS compatible encapsulation of ethernet frames over 34 | + existing IPv4 infrastructure. It is useful if the other endpoint 35 | + is a MikroTik router. 36 | + 37 | config IP_MROUTE 38 | bool "IP: multicast routing" 39 | depends on IP_MULTICAST 40 | -------------------------------------------------------------------------------- /kernel-patch/kernel-4.15.0-eoip-gre-demux.patch: -------------------------------------------------------------------------------- 1 | --- linux-4.9/include/net/gre.h.orig 2014-07-04 02:52:26.955400395 +0300 2 | +++ linux-4.9/include/net/gre.h 2014-06-13 23:12:31.745892381 +0300 3 | @@ -9,6 +9,13 @@ 4 | #define GREPROTO_MAX 2 5 | #define GRE_IP_PROTO_MAX 2 6 | 7 | +/* handle protocols with non-standard GRE header by ids that do not overlap 8 | + * with possible standard GRE protocol versions (0x00 - 0x7f) 9 | + */ 10 | +#define GREPROTO_NONSTD_BASE 0x80 11 | +#define GREPROTO_NONSTD_EOIP (0 + GREPROTO_NONSTD_BASE) 12 | +#define GREPROTO_NONSTD_MAX (1 + GREPROTO_NONSTD_BASE) 13 | + 14 | struct gre_protocol { 15 | int (*handler)(struct sk_buff *skb); 16 | void (*err_handler)(struct sk_buff *skb, u32 info); 17 | --- linux-4.9/net/ipv4/gre_demux.c.orig 2014-07-04 02:53:03.975398766 +0300 18 | +++ linux-4.9/net/ipv4/gre_demux.c 2014-06-16 00:10:05.118137863 +0300 19 | @@ -30,12 +30,18 @@ 20 | #include 21 | #include 22 | 23 | -static const struct gre_protocol __rcu *gre_proto[GREPROTO_MAX] __read_mostly; 24 | +#define GREPROTO_CNT \ 25 | + (GREPROTO_MAX + GREPROTO_NONSTD_MAX - GREPROTO_NONSTD_BASE) 26 | + 27 | +static const struct gre_protocol __rcu *gre_proto[GREPROTO_CNT] __read_mostly; 28 | 29 | int gre_add_protocol(const struct gre_protocol *proto, u8 version) 30 | { 31 | - if (version >= GREPROTO_MAX) 32 | - return -EINVAL; 33 | + if (version >= GREPROTO_NONSTD_BASE && version < GREPROTO_NONSTD_MAX) 34 | + version -= GREPROTO_NONSTD_BASE - GREPROTO_MAX; 35 | + else 36 | + if (version >= GREPROTO_MAX) 37 | + return -EINVAL; 38 | 39 | return (cmpxchg((const struct gre_protocol **)&gre_proto[version], NULL, proto) == NULL) ? 40 | 0 : -EBUSY; 41 | @@ -46,8 +52,11 @@ int gre_del_protocol(const struct gre_pr 42 | { 43 | int ret; 44 | 45 | - if (version >= GREPROTO_MAX) 46 | - return -EINVAL; 47 | + if (version >= GREPROTO_NONSTD_BASE && version < GREPROTO_NONSTD_MAX) 48 | + version -= GREPROTO_NONSTD_BASE - GREPROTO_MAX; 49 | + else 50 | + if (version >= GREPROTO_MAX) 51 | + return -EINVAL; 52 | 53 | ret = (cmpxchg((const struct gre_protocol **)&gre_proto[version], proto, NULL) == proto) ? 54 | 0 : -EBUSY; 55 | @@ -137,12 +146,22 @@ static int gre_rcv(struct sk_buff *skb) 56 | u8 ver; 57 | int ret; 58 | 59 | + /* the standard GRE header is 12 octets; the EOIP header is 8 60 | + * 4 octets long ethernet packet can not be valid 61 | + */ 62 | if (!pskb_may_pull(skb, 12)) 63 | goto drop; 64 | 65 | - ver = skb->data[1]&0x7f; 66 | - if (ver >= GREPROTO_MAX) 67 | - goto drop; 68 | + /* check for custom EOIP header */ 69 | + if (skb->data[0] == 0x20 && skb->data[1] == 0x01 && 70 | + skb->data[2] == 0x64 && skb->data[3] == 0x00) 71 | + ver = GREPROTO_NONSTD_EOIP - GREPROTO_NONSTD_BASE 72 | + + GREPROTO_MAX; 73 | + else { 74 | + ver = skb->data[1]&0x7f; 75 | + if (ver >= GREPROTO_MAX) 76 | + goto drop; 77 | + } 78 | 79 | rcu_read_lock(); 80 | proto = rcu_dereference(gre_proto[ver]); 81 | @@ -163,10 +182,19 @@ static void gre_err(struct sk_buff *skb, 82 | { 83 | const struct gre_protocol *proto; 84 | const struct iphdr *iph = (const struct iphdr *)skb->data; 85 | - u8 ver = skb->data[(iph->ihl<<2) + 1]&0x7f; 86 | + u8 ver; 87 | 88 | - if (ver >= GREPROTO_MAX) 89 | - return; 90 | + if (skb->data[(iph->ihl<<2) + 0] == 0x20 && 91 | + skb->data[(iph->ihl<<2) + 1] == 0x01 && 92 | + skb->data[(iph->ihl<<2) + 2] == 0x64 && 93 | + skb->data[(iph->ihl<<2) + 3] == 0x00) 94 | + ver = GREPROTO_NONSTD_EOIP - GREPROTO_NONSTD_BASE 95 | + + GREPROTO_MAX; 96 | + else { 97 | + ver = skb->data[(iph->ihl<<2) + 1]&0x7f; 98 | + if (ver >= GREPROTO_MAX) 99 | + return; 100 | + } 101 | 102 | rcu_read_lock(); 103 | proto = rcu_dereference(gre_proto[ver]); 104 | -------------------------------------------------------------------------------- /kernel-patch/kernel-4.19.0-eoip-buildconf.patch: -------------------------------------------------------------------------------- 1 | --- linux-3.15/net/ipv4/Makefile.orig 2014-06-14 00:22:46.749706936 +0300 2 | +++ linux-3.15/net/ipv4/Makefile 2014-06-14 00:23:53.257704010 +0300 3 | @@ -23,6 +23,7 @@ gre-y := gre_demux.o 4 | obj-$(CONFIG_NET_IPGRE_DEMUX) += gre.o 5 | obj-$(CONFIG_NET_IPGRE) += ip_gre.o 6 | obj-$(CONFIG_NET_IPVTI) += ip_vti.o 7 | +obj-$(CONFIG_NET_EOIP) += eoip.o 8 | obj-$(CONFIG_SYN_COOKIES) += syncookies.o 9 | obj-$(CONFIG_INET_AH) += ah4.o 10 | obj-$(CONFIG_INET_ESP) += esp4.o 11 | --- linux-3.15/net/ipv4/Kconfig.orig 2014-06-14 00:18:28.437718301 +0300 12 | +++ linux-3.15/net/ipv4/Kconfig 2014-06-14 00:22:32.273707573 +0300 13 | @@ -182,7 +182,7 @@ config NET_IPGRE_DEMUX 14 | tristate "IP: GRE demultiplexer" 15 | help 16 | This is helper module to demultiplex GRE packets on GRE version field criteria. 17 | - Required by ip_gre and pptp modules. 18 | + Required by ip_gre, pptp and eoip modules. 19 | 20 | config NET_IP_TUNNEL 21 | tristate 22 | @@ -212,6 +212,17 @@ config NET_IPGRE_BROADCAST 23 | Network), but can be distributed all over the Internet. If you want 24 | to do that, say Y here and to "IP multicast routing" below. 25 | 26 | +config NET_EOIP 27 | + tristate "IP: EOIP ethernet tunnels over IP" 28 | + depends on (IPV6 || IPV6=n) && NET_IPGRE_DEMUX 29 | + help 30 | + Tunneling means encapsulating data of one protocol type within 31 | + another protocol and sending it over a channel that understands the 32 | + encapsulating protocol. This particular tunneling driver implements 33 | + MikroTik RouterOS compatible encapsulation of ethernet frames over 34 | + existing IPv4 infrastructure. It is useful if the other endpoint 35 | + is a MikroTik router. 36 | + 37 | config IP_MROUTE 38 | bool "IP: multicast routing" 39 | depends on IP_MULTICAST 40 | -------------------------------------------------------------------------------- /kernel-patch/kernel-4.19.0-eoip-gre-demux.patch: -------------------------------------------------------------------------------- 1 | --- linux-3.15/include/net/gre.h.orig 2014-07-04 02:52:26.955400395 +0300 2 | +++ linux-3.15/include/net/gre.h 2014-06-13 23:12:31.745892381 +0300 3 | @@ -9,6 +9,13 @@ 4 | #define GREPROTO_MAX 2 5 | #define GRE_IP_PROTO_MAX 2 6 | 7 | +/* handle protocols with non-standard GRE header by ids that do not overlap 8 | + * with possible standard GRE protocol versions (0x00 - 0x7f) 9 | + */ 10 | +#define GREPROTO_NONSTD_BASE 0x80 11 | +#define GREPROTO_NONSTD_EOIP (0 + GREPROTO_NONSTD_BASE) 12 | +#define GREPROTO_NONSTD_MAX (1 + GREPROTO_NONSTD_BASE) 13 | + 14 | struct gre_protocol { 15 | int (*handler)(struct sk_buff *skb); 16 | void (*err_handler)(struct sk_buff *skb, u32 info); 17 | --- linux-3.15/net/ipv4/gre_demux.c.orig 2014-07-04 02:53:03.975398766 +0300 18 | +++ linux-3.15/net/ipv4/gre_demux.c 2014-06-16 00:10:05.118137863 +0300 19 | @@ -30,12 +30,18 @@ 20 | #include 21 | #include 22 | 23 | -static const struct gre_protocol __rcu *gre_proto[GREPROTO_MAX] __read_mostly; 24 | +#define GREPROTO_CNT \ 25 | + (GREPROTO_MAX + GREPROTO_NONSTD_MAX - GREPROTO_NONSTD_BASE) 26 | + 27 | +static const struct gre_protocol __rcu *gre_proto[GREPROTO_CNT] __read_mostly; 28 | 29 | int gre_add_protocol(const struct gre_protocol *proto, u8 version) 30 | { 31 | - if (version >= GREPROTO_MAX) 32 | - return -EINVAL; 33 | + if (version >= GREPROTO_NONSTD_BASE && version < GREPROTO_NONSTD_MAX) 34 | + version -= GREPROTO_NONSTD_BASE - GREPROTO_MAX; 35 | + else 36 | + if (version >= GREPROTO_MAX) 37 | + return -EINVAL; 38 | 39 | return (cmpxchg((const struct gre_protocol **)&gre_proto[version], NULL, proto) == NULL) ? 40 | 0 : -EBUSY; 41 | @@ -47,8 +53,11 @@ int gre_del_protocol(const struct gre_pr 42 | { 43 | int ret; 44 | 45 | - if (version >= GREPROTO_MAX) 46 | - return -EINVAL; 47 | + if (version >= GREPROTO_NONSTD_BASE && version < GREPROTO_NONSTD_MAX) 48 | + version -= GREPROTO_NONSTD_BASE - GREPROTO_MAX; 49 | + else 50 | + if (version >= GREPROTO_MAX) 51 | + return -EINVAL; 52 | 53 | ret = (cmpxchg((const struct gre_protocol **)&gre_proto[version], proto, NULL) == proto) ? 54 | 0 : -EBUSY; 55 | @@ -275,12 +284,22 @@ static int gre_rcv(struct sk_buff *skb) 56 | u8 ver; 57 | int ret; 58 | 59 | + /* the standard GRE header is 12 octets; the EOIP header is 8 60 | + * 4 octets long ethernet packet can not be valid 61 | + */ 62 | if (!pskb_may_pull(skb, 12)) 63 | goto drop; 64 | 65 | - ver = skb->data[1]&0x7f; 66 | - if (ver >= GREPROTO_MAX) 67 | - goto drop; 68 | + /* check for custom EOIP header */ 69 | + if (skb->data[0] == 0x20 && skb->data[1] == 0x01 && 70 | + skb->data[2] == 0x64 && skb->data[3] == 0x00) 71 | + ver = GREPROTO_NONSTD_EOIP - GREPROTO_NONSTD_BASE 72 | + + GREPROTO_MAX; 73 | + else { 74 | + ver = skb->data[1]&0x7f; 75 | + if (ver >= GREPROTO_MAX) 76 | + goto drop; 77 | + } 78 | 79 | rcu_read_lock(); 80 | proto = rcu_dereference(gre_proto[ver]); 81 | @@ -301,10 +320,19 @@ static void gre_err(struct sk_buff *skb, 82 | { 83 | const struct gre_protocol *proto; 84 | const struct iphdr *iph = (const struct iphdr *)skb->data; 85 | - u8 ver = skb->data[(iph->ihl<<2) + 1]&0x7f; 86 | + u8 ver; 87 | 88 | - if (ver >= GREPROTO_MAX) 89 | - return; 90 | + if (skb->data[(iph->ihl<<2) + 0] == 0x20 && 91 | + skb->data[(iph->ihl<<2) + 1] == 0x01 && 92 | + skb->data[(iph->ihl<<2) + 2] == 0x64 && 93 | + skb->data[(iph->ihl<<2) + 3] == 0x00) 94 | + ver = GREPROTO_NONSTD_EOIP - GREPROTO_NONSTD_BASE 95 | + + GREPROTO_MAX; 96 | + else { 97 | + ver = skb->data[(iph->ihl<<2) + 1]&0x7f; 98 | + if (ver >= GREPROTO_MAX) 99 | + return; 100 | + } 101 | 102 | rcu_read_lock(); 103 | proto = rcu_dereference(gre_proto[ver]); 104 | -------------------------------------------------------------------------------- /kernel-patch/kernel-4.9.0-eoip-buildconf.patch: -------------------------------------------------------------------------------- 1 | --- linux-3.15/net/ipv4/Makefile.orig 2014-06-14 00:22:46.749706936 +0300 2 | +++ linux-3.15/net/ipv4/Makefile 2014-06-14 00:23:53.257704010 +0300 3 | @@ -23,6 +23,7 @@ gre-y := gre_demux.o 4 | obj-$(CONFIG_NET_IPGRE_DEMUX) += gre.o 5 | obj-$(CONFIG_NET_IPGRE) += ip_gre.o 6 | obj-$(CONFIG_NET_IPVTI) += ip_vti.o 7 | +obj-$(CONFIG_NET_EOIP) += eoip.o 8 | obj-$(CONFIG_SYN_COOKIES) += syncookies.o 9 | obj-$(CONFIG_INET_AH) += ah4.o 10 | obj-$(CONFIG_INET_ESP) += esp4.o 11 | --- linux-3.15/net/ipv4/Kconfig.orig 2014-06-14 00:18:28.437718301 +0300 12 | +++ linux-3.15/net/ipv4/Kconfig 2014-06-14 00:22:32.273707573 +0300 13 | @@ -182,7 +182,7 @@ config NET_IPGRE_DEMUX 14 | tristate "IP: GRE demultiplexer" 15 | help 16 | This is helper module to demultiplex GRE packets on GRE version field criteria. 17 | - Required by ip_gre and pptp modules. 18 | + Required by ip_gre, pptp and eoip modules. 19 | 20 | config NET_IP_TUNNEL 21 | tristate 22 | @@ -212,6 +212,17 @@ config NET_IPGRE_BROADCAST 23 | Network), but can be distributed all over the Internet. If you want 24 | to do that, say Y here and to "IP multicast routing" below. 25 | 26 | +config NET_EOIP 27 | + tristate "IP: EOIP ethernet tunnels over IP" 28 | + depends on (IPV6 || IPV6=n) && NET_IPGRE_DEMUX 29 | + help 30 | + Tunneling means encapsulating data of one protocol type within 31 | + another protocol and sending it over a channel that understands the 32 | + encapsulating protocol. This particular tunneling driver implements 33 | + MikroTik RouterOS compatible encapsulation of ethernet frames over 34 | + existing IPv4 infrastructure. It is useful if the other endpoint 35 | + is a MikroTik router. 36 | + 37 | config IP_MROUTE 38 | bool "IP: multicast routing" 39 | depends on IP_MULTICAST 40 | -------------------------------------------------------------------------------- /kernel-patch/kernel-4.9.0-eoip-gre-demux.patch: -------------------------------------------------------------------------------- 1 | --- linux-4.9/include/net/gre.h.orig 2014-07-04 02:52:26.955400395 +0300 2 | +++ linux-4.9/include/net/gre.h 2014-06-13 23:12:31.745892381 +0300 3 | @@ -9,6 +9,13 @@ 4 | #define GREPROTO_MAX 2 5 | #define GRE_IP_PROTO_MAX 2 6 | 7 | +/* handle protocols with non-standard GRE header by ids that do not overlap 8 | + * with possible standard GRE protocol versions (0x00 - 0x7f) 9 | + */ 10 | +#define GREPROTO_NONSTD_BASE 0x80 11 | +#define GREPROTO_NONSTD_EOIP (0 + GREPROTO_NONSTD_BASE) 12 | +#define GREPROTO_NONSTD_MAX (1 + GREPROTO_NONSTD_BASE) 13 | + 14 | struct gre_protocol { 15 | int (*handler)(struct sk_buff *skb); 16 | void (*err_handler)(struct sk_buff *skb, u32 info); 17 | --- linux-4.9/net/ipv4/gre_demux.c.orig 2014-07-04 02:53:03.975398766 +0300 18 | +++ linux-4.9/net/ipv4/gre_demux.c 2014-06-16 00:10:05.118137863 +0300 19 | @@ -30,12 +30,18 @@ 20 | #include 21 | #include 22 | 23 | -static const struct gre_protocol __rcu *gre_proto[GREPROTO_MAX] __read_mostly; 24 | +#define GREPROTO_CNT \ 25 | + (GREPROTO_MAX + GREPROTO_NONSTD_MAX - GREPROTO_NONSTD_BASE) 26 | + 27 | +static const struct gre_protocol __rcu *gre_proto[GREPROTO_CNT] __read_mostly; 28 | 29 | int gre_add_protocol(const struct gre_protocol *proto, u8 version) 30 | { 31 | - if (version >= GREPROTO_MAX) 32 | - return -EINVAL; 33 | + if (version >= GREPROTO_NONSTD_BASE && version < GREPROTO_NONSTD_MAX) 34 | + version -= GREPROTO_NONSTD_BASE - GREPROTO_MAX; 35 | + else 36 | + if (version >= GREPROTO_MAX) 37 | + return -EINVAL; 38 | 39 | return (cmpxchg((const struct gre_protocol **)&gre_proto[version], NULL, proto) == NULL) ? 40 | 0 : -EBUSY; 41 | @@ -46,8 +52,11 @@ int gre_del_protocol(const struct gre_pr 42 | { 43 | int ret; 44 | 45 | - if (version >= GREPROTO_MAX) 46 | - return -EINVAL; 47 | + if (version >= GREPROTO_NONSTD_BASE && version < GREPROTO_NONSTD_MAX) 48 | + version -= GREPROTO_NONSTD_BASE - GREPROTO_MAX; 49 | + else 50 | + if (version >= GREPROTO_MAX) 51 | + return -EINVAL; 52 | 53 | ret = (cmpxchg((const struct gre_protocol **)&gre_proto[version], proto, NULL) == proto) ? 54 | 0 : -EBUSY; 55 | @@ -137,12 +146,22 @@ static int gre_rcv(struct sk_buff *skb) 56 | u8 ver; 57 | int ret; 58 | 59 | + /* the standard GRE header is 12 octets; the EOIP header is 8 60 | + * 4 octets long ethernet packet can not be valid 61 | + */ 62 | if (!pskb_may_pull(skb, 12)) 63 | goto drop; 64 | 65 | - ver = skb->data[1]&0x7f; 66 | - if (ver >= GREPROTO_MAX) 67 | - goto drop; 68 | + /* check for custom EOIP header */ 69 | + if (skb->data[0] == 0x20 && skb->data[1] == 0x01 && 70 | + skb->data[2] == 0x64 && skb->data[3] == 0x00) 71 | + ver = GREPROTO_NONSTD_EOIP - GREPROTO_NONSTD_BASE 72 | + + GREPROTO_MAX; 73 | + else { 74 | + ver = skb->data[1]&0x7f; 75 | + if (ver >= GREPROTO_MAX) 76 | + goto drop; 77 | + } 78 | 79 | rcu_read_lock(); 80 | proto = rcu_dereference(gre_proto[ver]); 81 | @@ -163,10 +182,19 @@ static void gre_err(struct sk_buff *skb, 82 | { 83 | const struct gre_protocol *proto; 84 | const struct iphdr *iph = (const struct iphdr *)skb->data; 85 | - u8 ver = skb->data[(iph->ihl<<2) + 1]&0x7f; 86 | + u8 ver; 87 | 88 | - if (ver >= GREPROTO_MAX) 89 | - return; 90 | + if (skb->data[(iph->ihl<<2) + 0] == 0x20 && 91 | + skb->data[(iph->ihl<<2) + 1] == 0x01 && 92 | + skb->data[(iph->ihl<<2) + 2] == 0x64 && 93 | + skb->data[(iph->ihl<<2) + 3] == 0x00) 94 | + ver = GREPROTO_NONSTD_EOIP - GREPROTO_NONSTD_BASE 95 | + + GREPROTO_MAX; 96 | + else { 97 | + ver = skb->data[(iph->ihl<<2) + 1]&0x7f; 98 | + if (ver >= GREPROTO_MAX) 99 | + return; 100 | + } 101 | 102 | rcu_read_lock(); 103 | proto = rcu_dereference(gre_proto[ver]); 104 | -------------------------------------------------------------------------------- /kernel-patch/kernel-5.17.0-eoip-buildconf.patch: -------------------------------------------------------------------------------- 1 | kernel-5.6.0-eoip-buildconf.patch -------------------------------------------------------------------------------- /kernel-patch/kernel-5.17.0-eoip-gre-demux.patch: -------------------------------------------------------------------------------- 1 | kernel-5.6.0-eoip-gre-demux.patch -------------------------------------------------------------------------------- /kernel-patch/kernel-5.6.0-eoip-buildconf.patch: -------------------------------------------------------------------------------- 1 | --- linux-3.15/net/ipv4/Makefile.orig 2014-06-14 00:22:46.749706936 +0300 2 | +++ linux-3.15/net/ipv4/Makefile 2014-06-14 00:23:53.257704010 +0300 3 | @@ -23,6 +23,7 @@ gre-y := gre_demux.o 4 | obj-$(CONFIG_NET_IPGRE_DEMUX) += gre.o 5 | obj-$(CONFIG_NET_IPGRE) += ip_gre.o 6 | obj-$(CONFIG_NET_IPVTI) += ip_vti.o 7 | +obj-$(CONFIG_NET_EOIP) += eoip.o 8 | obj-$(CONFIG_SYN_COOKIES) += syncookies.o 9 | obj-$(CONFIG_INET_AH) += ah4.o 10 | obj-$(CONFIG_INET_ESP) += esp4.o 11 | --- linux-3.15/net/ipv4/Kconfig.orig 2014-06-14 00:18:28.437718301 +0300 12 | +++ linux-3.15/net/ipv4/Kconfig 2014-06-14 00:22:32.273707573 +0300 13 | @@ -182,7 +182,7 @@ config NET_IPGRE_DEMUX 14 | tristate "IP: GRE demultiplexer" 15 | help 16 | This is helper module to demultiplex GRE packets on GRE version field criteria. 17 | - Required by ip_gre and pptp modules. 18 | + Required by ip_gre, pptp and eoip modules. 19 | 20 | config NET_IP_TUNNEL 21 | tristate 22 | @@ -212,6 +212,17 @@ config NET_IPGRE_BROADCAST 23 | Network), but can be distributed all over the Internet. If you want 24 | to do that, say Y here and to "IP multicast routing" below. 25 | 26 | +config NET_EOIP 27 | + tristate "IP: EOIP ethernet tunnels over IP" 28 | + depends on (IPV6 || IPV6=n) && NET_IPGRE_DEMUX 29 | + help 30 | + Tunneling means encapsulating data of one protocol type within 31 | + another protocol and sending it over a channel that understands the 32 | + encapsulating protocol. This particular tunneling driver implements 33 | + MikroTik RouterOS compatible encapsulation of ethernet frames over 34 | + existing IPv4 infrastructure. It is useful if the other endpoint 35 | + is a MikroTik router. 36 | + 37 | config IP_MROUTE 38 | bool "IP: multicast routing" 39 | depends on IP_MULTICAST 40 | -------------------------------------------------------------------------------- /kernel-patch/kernel-5.6.0-eoip-gre-demux.patch: -------------------------------------------------------------------------------- 1 | --- linux-5.6.16/include/net/gre.h.orig 2014-07-04 02:52:26.955400395 +0300 2 | +++ linux-5.6.16/include/net/gre.h 2014-06-13 23:12:31.745892381 +0300 3 | @@ -9,6 +9,13 @@ 4 | #define GREPROTO_MAX 2 5 | #define GRE_IP_PROTO_MAX 2 6 | 7 | +/* handle protocols with non-standard GRE header by ids that do not overlap 8 | + * with possible standard GRE protocol versions (0x00 - 0x7f) 9 | + */ 10 | +#define GREPROTO_NONSTD_BASE 0x80 11 | +#define GREPROTO_NONSTD_EOIP (0 + GREPROTO_NONSTD_BASE) 12 | +#define GREPROTO_NONSTD_MAX (1 + GREPROTO_NONSTD_BASE) 13 | + 14 | struct gre_protocol { 15 | int (*handler)(struct sk_buff *skb); 16 | void (*err_handler)(struct sk_buff *skb, u32 info); 17 | --- linux-5.6.16/net/ipv4/gre_demux.c.orig 2014-07-04 02:53:03.975398766 +0300 18 | +++ linux-5.6.16/net/ipv4/gre_demux.c 2014-06-16 00:10:05.118137863 +0300 19 | @@ -26,12 +26,18 @@ 20 | #include 21 | #include 22 | 23 | -static const struct gre_protocol __rcu *gre_proto[GREPROTO_MAX] __read_mostly; 24 | +#define GREPROTO_CNT \ 25 | + (GREPROTO_MAX + GREPROTO_NONSTD_MAX - GREPROTO_NONSTD_BASE) 26 | + 27 | +static const struct gre_protocol __rcu *gre_proto[GREPROTO_CNT] __read_mostly; 28 | 29 | int gre_add_protocol(const struct gre_protocol *proto, u8 version) 30 | { 31 | - if (version >= GREPROTO_MAX) 32 | - return -EINVAL; 33 | + if (version >= GREPROTO_NONSTD_BASE && version < GREPROTO_NONSTD_MAX) 34 | + version -= GREPROTO_NONSTD_BASE - GREPROTO_MAX; 35 | + else 36 | + if (version >= GREPROTO_MAX) 37 | + return -EINVAL; 38 | 39 | return (cmpxchg((const struct gre_protocol **)&gre_proto[version], NULL, proto) == NULL) ? 40 | 0 : -EBUSY; 41 | @@ -42,8 +48,11 @@ int gre_del_protocol(const struct gre_pr 42 | { 43 | int ret; 44 | 45 | - if (version >= GREPROTO_MAX) 46 | - return -EINVAL; 47 | + if (version >= GREPROTO_NONSTD_BASE && version < GREPROTO_NONSTD_MAX) 48 | + version -= GREPROTO_NONSTD_BASE - GREPROTO_MAX; 49 | + else 50 | + if (version >= GREPROTO_MAX) 51 | + return -EINVAL; 52 | 53 | ret = (cmpxchg((const struct gre_protocol **)&gre_proto[version], proto, NULL) == proto) ? 54 | 0 : -EBUSY; 55 | @@ -149,12 +158,22 @@ static int gre_rcv(struct sk_buff *skb) 56 | u8 ver; 57 | int ret; 58 | 59 | + /* the standard GRE header is 12 octets; the EOIP header is 8 60 | + * 4 octets long ethernet packet can not be valid 61 | + */ 62 | if (!pskb_may_pull(skb, 12)) 63 | goto drop; 64 | 65 | - ver = skb->data[1]&0x7f; 66 | - if (ver >= GREPROTO_MAX) 67 | - goto drop; 68 | + /* check for custom EOIP header */ 69 | + if (skb->data[0] == 0x20 && skb->data[1] == 0x01 && 70 | + skb->data[2] == 0x64 && skb->data[3] == 0x00) 71 | + ver = GREPROTO_NONSTD_EOIP - GREPROTO_NONSTD_BASE 72 | + + GREPROTO_MAX; 73 | + else { 74 | + ver = skb->data[1]&0x7f; 75 | + if (ver >= GREPROTO_MAX) 76 | + goto drop; 77 | + } 78 | 79 | rcu_read_lock(); 80 | proto = rcu_dereference(gre_proto[ver]); 81 | @@ -175,11 +194,20 @@ static int gre_err(struct sk_buff *skb, 82 | { 83 | const struct gre_protocol *proto; 84 | const struct iphdr *iph = (const struct iphdr *)skb->data; 85 | - u8 ver = skb->data[(iph->ihl<<2) + 1]&0x7f; 86 | + u8 ver; 87 | int err = 0; 88 | 89 | - if (ver >= GREPROTO_MAX) 90 | - return -EINVAL; 91 | + if (skb->data[(iph->ihl<<2) + 0] == 0x20 && 92 | + skb->data[(iph->ihl<<2) + 1] == 0x01 && 93 | + skb->data[(iph->ihl<<2) + 2] == 0x64 && 94 | + skb->data[(iph->ihl<<2) + 3] == 0x00) 95 | + ver = GREPROTO_NONSTD_EOIP - GREPROTO_NONSTD_BASE 96 | + + GREPROTO_MAX; 97 | + else { 98 | + ver = skb->data[(iph->ihl<<2) + 1]&0x7f; 99 | + if (ver >= GREPROTO_MAX) 100 | + return -EINVAL; 101 | + } 102 | 103 | rcu_read_lock(); 104 | proto = rcu_dereference(gre_proto[ver]); 105 | -------------------------------------------------------------------------------- /kernel-patch/kernel-6.0.0-eoip-buildconf.patch: -------------------------------------------------------------------------------- 1 | kernel-5.6.0-eoip-buildconf.patch -------------------------------------------------------------------------------- /kernel-patch/kernel-6.0.0-eoip-gre-demux.patch: -------------------------------------------------------------------------------- 1 | kernel-5.6.0-eoip-gre-demux.patch -------------------------------------------------------------------------------- /kernel-patch/kernel-6.1.0-eoip-buildconf.patch: -------------------------------------------------------------------------------- 1 | kernel-6.0.0-eoip-buildconf.patch -------------------------------------------------------------------------------- /kernel-patch/kernel-6.1.0-eoip-gre-demux.patch: -------------------------------------------------------------------------------- 1 | kernel-6.0.0-eoip-gre-demux.patch -------------------------------------------------------------------------------- /kernel-patch/kernel-6.12.0-eoip-buildconf.patch: -------------------------------------------------------------------------------- 1 | kernel-6.8.0-eoip-buildconf.patch -------------------------------------------------------------------------------- /kernel-patch/kernel-6.12.0-eoip-gre-demux.patch: -------------------------------------------------------------------------------- 1 | kernel-6.8.0-eoip-gre-demux.patch -------------------------------------------------------------------------------- /kernel-patch/kernel-6.6.0-eoip-buildconf.patch: -------------------------------------------------------------------------------- 1 | --- linux-3.15/net/ipv4/Makefile 2 | +++ linux-3.15/net/ipv4/Makefile 3 | @@ -23,6 +23,7 @@ gre-y := gre_demux.o 4 | obj-$(CONFIG_NET_IPGRE_DEMUX) += gre.o 5 | obj-$(CONFIG_NET_IPGRE) += ip_gre.o 6 | obj-$(CONFIG_NET_IPVTI) += ip_vti.o 7 | +obj-$(CONFIG_NET_EOIP) += eoip.o 8 | obj-$(CONFIG_SYN_COOKIES) += syncookies.o 9 | obj-$(CONFIG_INET_AH) += ah4.o 10 | obj-$(CONFIG_INET_ESP) += esp4.o 11 | --- linux-6.79/net/ipv4/Kconfig 12 | +++ linux-6.79/net/ipv4/Kconfig 13 | @@ -181,7 +181,7 @@ config NET_IPGRE_DEMUX 14 | tristate "IP: GRE demultiplexer" 15 | help 16 | This is helper module to demultiplex GRE packets on GRE version field criteria. 17 | - Required by ip_gre and pptp modules. 18 | + Required by ip_gre, pptp and eoip modules. 19 | 20 | config NET_IP_TUNNEL 21 | tristate 22 | @@ -217,6 +217,17 @@ config IP_MROUTE_COMMON 23 | bool 24 | depends on IP_MROUTE || IPV6_MROUTE 25 | 26 | +config NET_EOIP 27 | + tristate "IP: EOIP ethernet tunnels over IP" 28 | + depends on (IPV6 || IPV6=n) && NET_IPGRE_DEMUX 29 | + help 30 | + Tunneling means encapsulating data of one protocol type within 31 | + another protocol and sending it over a channel that understands the 32 | + encapsulating protocol. This particular tunneling driver implements 33 | + MikroTik RouterOS compatible encapsulation of ethernet frames over 34 | + existing IPv4 infrastructure. It is useful if the other endpoint 35 | + is a MikroTik router. 36 | + 37 | config IP_MROUTE 38 | bool "IP: multicast routing" 39 | depends on IP_MULTICAST 40 | -------------------------------------------------------------------------------- /kernel-patch/kernel-6.6.0-eoip-gre-demux.patch: -------------------------------------------------------------------------------- 1 | kernel-6.1.0-eoip-gre-demux.patch -------------------------------------------------------------------------------- /kernel-patch/kernel-6.6.0-eoip.patch: -------------------------------------------------------------------------------- 1 | kernel-6.1.0-eoip.patch -------------------------------------------------------------------------------- /kernel-patch/kernel-6.8.0-eoip-buildconf.patch: -------------------------------------------------------------------------------- 1 | kernel-6.6.0-eoip-buildconf.patch -------------------------------------------------------------------------------- /kernel-patch/kernel-6.8.0-eoip-gre-demux.patch: -------------------------------------------------------------------------------- 1 | kernel-6.1.0-eoip-gre-demux.patch -------------------------------------------------------------------------------- /libnetlink.c: -------------------------------------------------------------------------------- 1 | /* 2 | * libnetlink.c RTnetlink service routines. 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 7 | * 2 of the License, or (at your option) any later version. 8 | * 9 | * Authors: Alexey Kuznetsov, 10 | * 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "libnetlink.h" 25 | 26 | int rcvbuf = 1024 * 1024; 27 | 28 | void rtnl_close(struct rtnl_handle *rth) 29 | { 30 | if (rth->fd >= 0) { 31 | close(rth->fd); 32 | rth->fd = -1; 33 | } 34 | } 35 | 36 | int rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions, 37 | int protocol) 38 | { 39 | socklen_t addr_len; 40 | int sndbuf = 32768; 41 | 42 | memset(rth, 0, sizeof(*rth)); 43 | 44 | rth->fd = socket(AF_NETLINK, SOCK_RAW, protocol); 45 | if (rth->fd < 0) { 46 | perror("Cannot open netlink socket"); 47 | return -1; 48 | } 49 | 50 | if (setsockopt(rth->fd,SOL_SOCKET,SO_SNDBUF,&sndbuf,sizeof(sndbuf)) < 0) { 51 | perror("SO_SNDBUF"); 52 | return -1; 53 | } 54 | 55 | if (setsockopt(rth->fd,SOL_SOCKET,SO_RCVBUF,&rcvbuf,sizeof(rcvbuf)) < 0) { 56 | perror("SO_RCVBUF"); 57 | return -1; 58 | } 59 | 60 | memset(&rth->local, 0, sizeof(rth->local)); 61 | rth->local.nl_family = AF_NETLINK; 62 | rth->local.nl_groups = subscriptions; 63 | 64 | if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) { 65 | perror("Cannot bind netlink socket"); 66 | return -1; 67 | } 68 | addr_len = sizeof(rth->local); 69 | if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0) { 70 | perror("Cannot getsockname"); 71 | return -1; 72 | } 73 | if (addr_len != sizeof(rth->local)) { 74 | fprintf(stderr, "Wrong address length %d\n", addr_len); 75 | return -1; 76 | } 77 | if (rth->local.nl_family != AF_NETLINK) { 78 | fprintf(stderr, "Wrong address family %d\n", rth->local.nl_family); 79 | return -1; 80 | } 81 | rth->seq = time(NULL); 82 | return 0; 83 | } 84 | 85 | int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions) 86 | { 87 | return rtnl_open_byproto(rth, subscriptions, NETLINK_ROUTE); 88 | } 89 | 90 | int rtnl_wilddump_request(struct rtnl_handle *rth, int family, int type) 91 | { 92 | struct { 93 | struct nlmsghdr nlh; 94 | struct rtgenmsg g; 95 | __u16 align_rta; /* attribute has to be 32bit aligned */ 96 | struct rtattr ext_req; 97 | __u32 ext_filter_mask; 98 | } req; 99 | 100 | memset(&req, 0, sizeof(req)); 101 | req.nlh.nlmsg_len = sizeof(req); 102 | req.nlh.nlmsg_type = type; 103 | req.nlh.nlmsg_flags = NLM_F_DUMP|NLM_F_REQUEST; 104 | req.nlh.nlmsg_pid = 0; 105 | req.nlh.nlmsg_seq = rth->dump = ++rth->seq; 106 | req.g.rtgen_family = family; 107 | 108 | req.ext_req.rta_type = IFLA_EXT_MASK; 109 | req.ext_req.rta_len = RTA_LENGTH(sizeof(__u32)); 110 | req.ext_filter_mask = RTEXT_FILTER_VF; 111 | 112 | return send(rth->fd, (void*)&req, sizeof(req), 0); 113 | } 114 | 115 | int rtnl_send(struct rtnl_handle *rth, const void *buf, int len) 116 | { 117 | return send(rth->fd, buf, len, 0); 118 | } 119 | 120 | int rtnl_send_check(struct rtnl_handle *rth, const void *buf, int len) 121 | { 122 | struct nlmsghdr *h; 123 | int status; 124 | char resp[1024]; 125 | 126 | status = send(rth->fd, buf, len, 0); 127 | if (status < 0) 128 | return status; 129 | 130 | /* Check for immediate errors */ 131 | status = recv(rth->fd, resp, sizeof(resp), MSG_DONTWAIT|MSG_PEEK); 132 | if (status < 0) { 133 | if (errno == EAGAIN) 134 | return 0; 135 | return -1; 136 | } 137 | 138 | for (h = (struct nlmsghdr *)resp; NLMSG_OK(h, status); 139 | h = NLMSG_NEXT(h, status)) { 140 | if (h->nlmsg_type == NLMSG_ERROR) { 141 | struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); 142 | if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) 143 | fprintf(stderr, "ERROR truncated\n"); 144 | else 145 | errno = -err->error; 146 | return -1; 147 | } 148 | } 149 | 150 | return 0; 151 | } 152 | 153 | int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len) 154 | { 155 | struct nlmsghdr nlh; 156 | struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK }; 157 | struct iovec iov[2] = { 158 | { .iov_base = &nlh, .iov_len = sizeof(nlh) }, 159 | { .iov_base = req, .iov_len = len } 160 | }; 161 | struct msghdr msg = { 162 | .msg_name = &nladdr, 163 | .msg_namelen = sizeof(nladdr), 164 | .msg_iov = iov, 165 | .msg_iovlen = 2, 166 | }; 167 | 168 | nlh.nlmsg_len = NLMSG_LENGTH(len); 169 | nlh.nlmsg_type = type; 170 | nlh.nlmsg_flags = NLM_F_DUMP|NLM_F_REQUEST; 171 | nlh.nlmsg_pid = 0; 172 | nlh.nlmsg_seq = rth->dump = ++rth->seq; 173 | 174 | return sendmsg(rth->fd, &msg, 0); 175 | } 176 | 177 | int rtnl_dump_filter_l(struct rtnl_handle *rth, 178 | const struct rtnl_dump_filter_arg *arg) 179 | { 180 | struct sockaddr_nl nladdr; 181 | struct iovec iov; 182 | struct msghdr msg = { 183 | .msg_name = &nladdr, 184 | .msg_namelen = sizeof(nladdr), 185 | .msg_iov = &iov, 186 | .msg_iovlen = 1, 187 | }; 188 | char buf[16384]; 189 | 190 | iov.iov_base = buf; 191 | while (1) { 192 | int status; 193 | const struct rtnl_dump_filter_arg *a; 194 | int found_done = 0; 195 | int msglen = 0; 196 | 197 | iov.iov_len = sizeof(buf); 198 | status = recvmsg(rth->fd, &msg, 0); 199 | 200 | if (status < 0) { 201 | if (errno == EINTR || errno == EAGAIN) 202 | continue; 203 | fprintf(stderr, "netlink receive error %s (%d)\n", 204 | strerror(errno), errno); 205 | return -1; 206 | } 207 | 208 | if (status == 0) { 209 | fprintf(stderr, "EOF on netlink\n"); 210 | return -1; 211 | } 212 | 213 | for (a = arg; a->filter; a++) { 214 | struct nlmsghdr *h = (struct nlmsghdr*)buf; 215 | msglen = status; 216 | 217 | while (NLMSG_OK(h, msglen)) { 218 | int err; 219 | 220 | if (nladdr.nl_pid != 0 || 221 | h->nlmsg_pid != rth->local.nl_pid || 222 | h->nlmsg_seq != rth->dump) 223 | goto skip_it; 224 | 225 | if (h->nlmsg_type == NLMSG_DONE) { 226 | found_done = 1; 227 | break; /* process next filter */ 228 | } 229 | if (h->nlmsg_type == NLMSG_ERROR) { 230 | struct nlmsgerr *lerr = (struct nlmsgerr*)NLMSG_DATA(h); 231 | 232 | if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) { 233 | fprintf(stderr, 234 | "ERROR truncated\n"); 235 | } else { 236 | errno = -lerr->error; 237 | perror("RTNETLINK answers"); 238 | } 239 | return -1; 240 | } 241 | err = a->filter(&nladdr, h, a->arg1); 242 | if (err < 0) 243 | return err; 244 | 245 | skip_it: 246 | h = NLMSG_NEXT(h, msglen); 247 | } 248 | } 249 | 250 | if (found_done) 251 | return 0; 252 | 253 | if (msg.msg_flags & MSG_TRUNC) { 254 | fprintf(stderr, "Message truncated\n"); 255 | continue; 256 | } 257 | if (msglen) { 258 | fprintf(stderr, "!!!Remnant of size %d\n", msglen); 259 | exit(1); 260 | } 261 | } 262 | } 263 | 264 | int rtnl_dump_filter(struct rtnl_handle *rth, 265 | rtnl_filter_t filter, 266 | void *arg1) 267 | { 268 | const struct rtnl_dump_filter_arg a[2] = { 269 | { .filter = filter, .arg1 = arg1, }, 270 | { .filter = NULL, .arg1 = NULL, }, 271 | }; 272 | 273 | return rtnl_dump_filter_l(rth, a); 274 | } 275 | 276 | int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer, 277 | unsigned groups, struct nlmsghdr *answer) 278 | { 279 | ssize_t status; 280 | unsigned seq; 281 | struct nlmsghdr *h; 282 | struct sockaddr_nl nladdr; 283 | struct iovec iov = { 284 | .iov_base = (void*) n, 285 | .iov_len = n->nlmsg_len 286 | }; 287 | struct msghdr msg = { 288 | .msg_name = &nladdr, 289 | .msg_namelen = sizeof(nladdr), 290 | .msg_iov = &iov, 291 | .msg_iovlen = 1, 292 | }; 293 | char buf[16384]; 294 | 295 | memset(&nladdr, 0, sizeof(nladdr)); 296 | nladdr.nl_family = AF_NETLINK; 297 | nladdr.nl_pid = peer; 298 | nladdr.nl_groups = groups; 299 | 300 | n->nlmsg_seq = seq = ++rtnl->seq; 301 | 302 | if (answer == NULL) 303 | n->nlmsg_flags |= NLM_F_ACK; 304 | 305 | status = sendmsg(rtnl->fd, &msg, 0); 306 | 307 | if (status < 0) { 308 | perror("Cannot talk to rtnetlink"); 309 | return -1; 310 | } 311 | 312 | memset(buf,0,sizeof(buf)); 313 | 314 | iov.iov_base = buf; 315 | 316 | while (1) { 317 | iov.iov_len = sizeof(buf); 318 | status = recvmsg(rtnl->fd, &msg, 0); 319 | 320 | if (status < 0) { 321 | if (errno == EINTR || errno == EAGAIN) 322 | continue; 323 | fprintf(stderr, "netlink receive error %s (%d)\n", 324 | strerror(errno), errno); 325 | return -1; 326 | } 327 | if (status == 0) { 328 | fprintf(stderr, "EOF on netlink\n"); 329 | return -1; 330 | } 331 | if (msg.msg_namelen != sizeof(nladdr)) { 332 | fprintf(stderr, "sender address length == %d\n", msg.msg_namelen); 333 | exit(1); 334 | } 335 | for (h = (struct nlmsghdr*)buf; status >= (ssize_t)sizeof(*h); ) { 336 | int len = h->nlmsg_len; 337 | ssize_t l = len - sizeof(*h); 338 | 339 | if (l < 0 || len>status) { 340 | if (msg.msg_flags & MSG_TRUNC) { 341 | fprintf(stderr, "Truncated message\n"); 342 | return -1; 343 | } 344 | fprintf(stderr, "!!!malformed message: len=%d\n", len); 345 | exit(1); 346 | } 347 | 348 | if (nladdr.nl_pid != (uint32_t)peer || 349 | h->nlmsg_pid != rtnl->local.nl_pid || 350 | h->nlmsg_seq != seq) { 351 | /* Don't forget to skip that message. */ 352 | status -= NLMSG_ALIGN(len); 353 | h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); 354 | continue; 355 | } 356 | 357 | if (h->nlmsg_type == NLMSG_ERROR) { 358 | struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); 359 | if (l < (ssize_t)sizeof(struct nlmsgerr)) { 360 | fprintf(stderr, "ERROR truncated\n"); 361 | } else { 362 | errno = -err->error; 363 | if (errno == 0) { 364 | if (answer) 365 | memcpy(answer, h, h->nlmsg_len); 366 | return 0; 367 | } 368 | perror("RTNETLINK answers"); 369 | } 370 | return -1; 371 | } 372 | if (answer) { 373 | memcpy(answer, h, h->nlmsg_len); 374 | return 0; 375 | } 376 | 377 | fprintf(stderr, "Unexpected reply!!!\n"); 378 | 379 | status -= NLMSG_ALIGN(len); 380 | h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); 381 | } 382 | if (msg.msg_flags & MSG_TRUNC) { 383 | fprintf(stderr, "Message truncated\n"); 384 | continue; 385 | } 386 | if (status) { 387 | fprintf(stderr, "!!!Remnant of size %zd\n", status); 388 | exit(1); 389 | } 390 | } 391 | } 392 | 393 | int rtnl_listen(struct rtnl_handle *rtnl, 394 | rtnl_filter_t handler, 395 | void *jarg) 396 | { 397 | struct nlmsghdr *h; 398 | struct sockaddr_nl nladdr; 399 | struct iovec iov; 400 | struct msghdr msg = { 401 | .msg_name = &nladdr, 402 | .msg_namelen = sizeof(nladdr), 403 | .msg_iov = &iov, 404 | .msg_iovlen = 1, 405 | }; 406 | char buf[8192]; 407 | 408 | memset(&nladdr, 0, sizeof(nladdr)); 409 | nladdr.nl_family = AF_NETLINK; 410 | nladdr.nl_pid = 0; 411 | nladdr.nl_groups = 0; 412 | 413 | iov.iov_base = buf; 414 | while (1) { 415 | int status; 416 | 417 | iov.iov_len = sizeof(buf); 418 | status = recvmsg(rtnl->fd, &msg, 0); 419 | 420 | if (status < 0) { 421 | if (errno == EINTR || errno == EAGAIN) 422 | continue; 423 | fprintf(stderr, "netlink receive error %s (%d)\n", 424 | strerror(errno), errno); 425 | if (errno == ENOBUFS) 426 | continue; 427 | return -1; 428 | } 429 | if (status == 0) { 430 | fprintf(stderr, "EOF on netlink\n"); 431 | return -1; 432 | } 433 | if (msg.msg_namelen != sizeof(nladdr)) { 434 | fprintf(stderr, "Sender address length == %d\n", msg.msg_namelen); 435 | exit(1); 436 | } 437 | for (h = (struct nlmsghdr*)buf; status >= (ssize_t)sizeof(*h); ) { 438 | int err; 439 | int len = h->nlmsg_len; 440 | int l = len - sizeof(*h); 441 | 442 | if (l<0 || len>status) { 443 | if (msg.msg_flags & MSG_TRUNC) { 444 | fprintf(stderr, "Truncated message\n"); 445 | return -1; 446 | } 447 | fprintf(stderr, "!!!malformed message: len=%d\n", len); 448 | exit(1); 449 | } 450 | 451 | err = handler(&nladdr, h, jarg); 452 | if (err < 0) 453 | return err; 454 | 455 | status -= NLMSG_ALIGN(len); 456 | h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); 457 | } 458 | if (msg.msg_flags & MSG_TRUNC) { 459 | fprintf(stderr, "Message truncated\n"); 460 | continue; 461 | } 462 | if (status) { 463 | fprintf(stderr, "!!!Remnant of size %d\n", status); 464 | exit(1); 465 | } 466 | } 467 | } 468 | 469 | int rtnl_from_file(FILE *rtnl, rtnl_filter_t handler, 470 | void *jarg) 471 | { 472 | struct sockaddr_nl nladdr; 473 | char buf[8192]; 474 | struct nlmsghdr *h = (void*)buf; 475 | 476 | memset(&nladdr, 0, sizeof(nladdr)); 477 | nladdr.nl_family = AF_NETLINK; 478 | nladdr.nl_pid = 0; 479 | nladdr.nl_groups = 0; 480 | 481 | while (1) { 482 | int err, len; 483 | int status; 484 | int l; 485 | 486 | status = fread(&buf, 1, sizeof(*h), rtnl); 487 | 488 | if (status < 0) { 489 | if (errno == EINTR) 490 | continue; 491 | perror("rtnl_from_file: fread"); 492 | return -1; 493 | } 494 | if (status == 0) 495 | return 0; 496 | 497 | len = h->nlmsg_len; 498 | l = len - sizeof(*h); 499 | 500 | if (l<0 || len>(ssize_t)sizeof(buf)) { 501 | fprintf(stderr, "!!!malformed message: len=%d @%ld\n", 502 | len, ftell(rtnl)); 503 | return -1; 504 | } 505 | 506 | status = fread(NLMSG_DATA(h), 1, NLMSG_ALIGN(l), rtnl); 507 | 508 | if (status < 0) { 509 | perror("rtnl_from_file: fread"); 510 | return -1; 511 | } 512 | if (status < l) { 513 | fprintf(stderr, "rtnl-from_file: truncated message\n"); 514 | return -1; 515 | } 516 | 517 | err = handler(&nladdr, h, jarg); 518 | if (err < 0) 519 | return err; 520 | } 521 | } 522 | 523 | int addattr(struct nlmsghdr *n, int maxlen, int type) 524 | { 525 | return addattr_l(n, maxlen, type, NULL, 0); 526 | } 527 | 528 | int addattr8(struct nlmsghdr *n, int maxlen, int type, __u8 data) 529 | { 530 | return addattr_l(n, maxlen, type, &data, sizeof(__u8)); 531 | } 532 | 533 | int addattr16(struct nlmsghdr *n, int maxlen, int type, __u16 data) 534 | { 535 | return addattr_l(n, maxlen, type, &data, sizeof(__u16)); 536 | } 537 | 538 | int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data) 539 | { 540 | return addattr_l(n, maxlen, type, &data, sizeof(__u32)); 541 | } 542 | 543 | int addattr64(struct nlmsghdr *n, int maxlen, int type, __u64 data) 544 | { 545 | return addattr_l(n, maxlen, type, &data, sizeof(__u64)); 546 | } 547 | 548 | int addattrstrz(struct nlmsghdr *n, int maxlen, int type, const char *str) 549 | { 550 | return addattr_l(n, maxlen, type, str, strlen(str)+1); 551 | } 552 | 553 | int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data, 554 | int alen) 555 | { 556 | int len = RTA_LENGTH(alen); 557 | struct rtattr *rta; 558 | 559 | if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > (size_t)maxlen) { 560 | fprintf(stderr, "addattr_l ERROR: message exceeded bound of %d\n",maxlen); 561 | return -1; 562 | } 563 | rta = NLMSG_TAIL(n); 564 | rta->rta_type = type; 565 | rta->rta_len = len; 566 | if (data) 567 | memcpy(RTA_DATA(rta), data, alen); 568 | n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len); 569 | return 0; 570 | } 571 | 572 | int addraw_l(struct nlmsghdr *n, int maxlen, const void *data, int len) 573 | { 574 | if (NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len) > (size_t)maxlen) { 575 | fprintf(stderr, "addraw_l ERROR: message exceeded bound of %d\n",maxlen); 576 | return -1; 577 | } 578 | 579 | memcpy(NLMSG_TAIL(n), data, len); 580 | memset((void *) NLMSG_TAIL(n) + len, 0, NLMSG_ALIGN(len) - len); 581 | n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len); 582 | return 0; 583 | } 584 | 585 | struct rtattr *addattr_nest(struct nlmsghdr *n, int maxlen, int type) 586 | { 587 | struct rtattr *nest = NLMSG_TAIL(n); 588 | 589 | addattr_l(n, maxlen, type, NULL, 0); 590 | return nest; 591 | } 592 | 593 | int addattr_nest_end(struct nlmsghdr *n, struct rtattr *nest) 594 | { 595 | nest->rta_len = (void *)NLMSG_TAIL(n) - (void *)nest; 596 | return n->nlmsg_len; 597 | } 598 | 599 | struct rtattr *addattr_nest_compat(struct nlmsghdr *n, int maxlen, int type, 600 | const void *data, int len) 601 | { 602 | struct rtattr *start = NLMSG_TAIL(n); 603 | 604 | addattr_l(n, maxlen, type, data, len); 605 | addattr_nest(n, maxlen, type); 606 | return start; 607 | } 608 | 609 | int addattr_nest_compat_end(struct nlmsghdr *n, struct rtattr *start) 610 | { 611 | struct rtattr *nest = (void *)start + NLMSG_ALIGN(start->rta_len); 612 | 613 | start->rta_len = (void *)NLMSG_TAIL(n) - (void *)start; 614 | addattr_nest_end(n, nest); 615 | return n->nlmsg_len; 616 | } 617 | 618 | int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data) 619 | { 620 | int len = RTA_LENGTH(4); 621 | struct rtattr *subrta; 622 | 623 | if (RTA_ALIGN(rta->rta_len) + len > (size_t)maxlen) { 624 | fprintf(stderr,"rta_addattr32: Error! max allowed bound %d exceeded\n",maxlen); 625 | return -1; 626 | } 627 | subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len)); 628 | subrta->rta_type = type; 629 | subrta->rta_len = len; 630 | memcpy(RTA_DATA(subrta), &data, 4); 631 | rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len; 632 | return 0; 633 | } 634 | 635 | int rta_addattr_l(struct rtattr *rta, int maxlen, int type, 636 | const void *data, int alen) 637 | { 638 | struct rtattr *subrta; 639 | int len = RTA_LENGTH(alen); 640 | 641 | if (RTA_ALIGN(rta->rta_len) + RTA_ALIGN(len) > (size_t)maxlen) { 642 | fprintf(stderr,"rta_addattr_l: Error! max allowed bound %d exceeded\n",maxlen); 643 | return -1; 644 | } 645 | subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len)); 646 | subrta->rta_type = type; 647 | subrta->rta_len = len; 648 | memcpy(RTA_DATA(subrta), data, alen); 649 | rta->rta_len = NLMSG_ALIGN(rta->rta_len) + RTA_ALIGN(len); 650 | return 0; 651 | } 652 | 653 | int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) 654 | { 655 | memset(tb, 0, sizeof(struct rtattr *) * (max + 1)); 656 | while (RTA_OK(rta, len)) { 657 | if ((rta->rta_type <= max) && (!tb[rta->rta_type])) 658 | tb[rta->rta_type] = rta; 659 | rta = RTA_NEXT(rta,len); 660 | } 661 | //if (len) 662 | // fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len); 663 | return 0; 664 | } 665 | 666 | int parse_rtattr_byindex(struct rtattr *tb[], int max, struct rtattr *rta, int len) 667 | { 668 | int i = 0; 669 | 670 | memset(tb, 0, sizeof(struct rtattr *) * max); 671 | while (RTA_OK(rta, len)) { 672 | if (rta->rta_type <= max && i < max) 673 | tb[i++] = rta; 674 | rta = RTA_NEXT(rta,len); 675 | } 676 | if (len) 677 | fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len); 678 | return i; 679 | } 680 | 681 | int __parse_rtattr_nested_compat(struct rtattr *tb[], int max, struct rtattr *rta, 682 | int len) 683 | { 684 | if (RTA_PAYLOAD(rta) < (size_t)len) 685 | return -1; 686 | if (RTA_PAYLOAD(rta) >= RTA_ALIGN(len) + sizeof(struct rtattr)) { 687 | rta = RTA_DATA(rta) + RTA_ALIGN(len); 688 | return parse_rtattr_nested(tb, max, rta); 689 | } 690 | memset(tb, 0, sizeof(struct rtattr *) * (max + 1)); 691 | return 0; 692 | } 693 | -------------------------------------------------------------------------------- /libnetlink.h: -------------------------------------------------------------------------------- 1 | #ifndef __LIBNETLINK_H__ 2 | #define __LIBNETLINK_H__ 1 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | struct rtnl_handle 13 | { 14 | int fd; 15 | struct sockaddr_nl local; 16 | struct sockaddr_nl peer; 17 | __u32 seq; 18 | __u32 dump; 19 | }; 20 | 21 | extern int rcvbuf; 22 | 23 | extern int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions); 24 | extern int rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions, int protocol); 25 | extern void rtnl_close(struct rtnl_handle *rth); 26 | extern int rtnl_wilddump_request(struct rtnl_handle *rth, int fam, int type); 27 | extern int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len); 28 | 29 | typedef int (*rtnl_filter_t)(const struct sockaddr_nl *, 30 | struct nlmsghdr *n, void *); 31 | 32 | struct rtnl_dump_filter_arg 33 | { 34 | rtnl_filter_t filter; 35 | void *arg1; 36 | }; 37 | 38 | extern int rtnl_dump_filter_l(struct rtnl_handle *rth, 39 | const struct rtnl_dump_filter_arg *arg); 40 | extern int rtnl_dump_filter(struct rtnl_handle *rth, rtnl_filter_t filter, 41 | void *arg); 42 | extern int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer, 43 | unsigned groups, struct nlmsghdr *answer); 44 | extern int rtnl_send(struct rtnl_handle *rth, const void *buf, int); 45 | extern int rtnl_send_check(struct rtnl_handle *rth, const void *buf, int); 46 | 47 | extern int addattr(struct nlmsghdr *n, int maxlen, int type); 48 | extern int addattr8(struct nlmsghdr *n, int maxlen, int type, __u8 data); 49 | extern int addattr16(struct nlmsghdr *n, int maxlen, int type, __u16 data); 50 | extern int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data); 51 | extern int addattr64(struct nlmsghdr *n, int maxlen, int type, __u64 data); 52 | extern int addattrstrz(struct nlmsghdr *n, int maxlen, int type, const char *data); 53 | 54 | extern int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data, int alen); 55 | extern int addraw_l(struct nlmsghdr *n, int maxlen, const void *data, int len); 56 | extern struct rtattr *addattr_nest(struct nlmsghdr *n, int maxlen, int type); 57 | extern int addattr_nest_end(struct nlmsghdr *n, struct rtattr *nest); 58 | extern struct rtattr *addattr_nest_compat(struct nlmsghdr *n, int maxlen, int type, const void *data, int len); 59 | extern int addattr_nest_compat_end(struct nlmsghdr *n, struct rtattr *nest); 60 | extern int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data); 61 | extern int rta_addattr_l(struct rtattr *rta, int maxlen, int type, const void *data, int alen); 62 | 63 | extern int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len); 64 | extern int parse_rtattr_byindex(struct rtattr *tb[], int max, struct rtattr *rta, int len); 65 | extern int __parse_rtattr_nested_compat(struct rtattr *tb[], int max, struct rtattr *rta, int len); 66 | 67 | #define parse_rtattr_nested(tb, max, rta) \ 68 | (parse_rtattr((tb), (max), RTA_DATA(rta), RTA_PAYLOAD(rta))) 69 | 70 | #define parse_rtattr_nested_compat(tb, max, rta, data, len) \ 71 | ({ data = RTA_PAYLOAD(rta) >= len ? RTA_DATA(rta) : NULL; \ 72 | __parse_rtattr_nested_compat(tb, max, rta, len); }) 73 | 74 | static inline __u8 rta_getattr_u8(const struct rtattr *rta) 75 | { 76 | return *(__u8 *)RTA_DATA(rta); 77 | } 78 | static inline __u16 rta_getattr_u16(const struct rtattr *rta) 79 | { 80 | return *(__u16 *)RTA_DATA(rta); 81 | } 82 | static inline __u32 rta_getattr_u32(const struct rtattr *rta) 83 | { 84 | return *(__u32 *)RTA_DATA(rta); 85 | } 86 | static inline __u64 rta_getattr_u64(const struct rtattr *rta) 87 | { 88 | __u64 tmp; 89 | memcpy(&tmp, RTA_DATA(rta), sizeof(__u64)); 90 | return tmp; 91 | } 92 | static inline const char *rta_getattr_str(const struct rtattr *rta) 93 | { 94 | return (const char *)RTA_DATA(rta); 95 | } 96 | 97 | extern int rtnl_listen(struct rtnl_handle *, rtnl_filter_t handler, 98 | void *jarg); 99 | extern int rtnl_from_file(FILE *, rtnl_filter_t handler, 100 | void *jarg); 101 | 102 | #define NLMSG_TAIL(nmsg) \ 103 | ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) 104 | 105 | #ifndef IFA_RTA 106 | #define IFA_RTA(r) \ 107 | ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg)))) 108 | #endif 109 | #ifndef IFA_PAYLOAD 110 | #define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrmsg)) 111 | #endif 112 | 113 | #ifndef IFLA_RTA 114 | #define IFLA_RTA(r) \ 115 | ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg)))) 116 | #endif 117 | #ifndef IFLA_PAYLOAD 118 | #define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg)) 119 | #endif 120 | 121 | #ifndef NDA_RTA 122 | #define NDA_RTA(r) \ 123 | ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg)))) 124 | #endif 125 | #ifndef NDA_PAYLOAD 126 | #define NDA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ndmsg)) 127 | #endif 128 | 129 | #ifndef NDTA_RTA 130 | #define NDTA_RTA(r) \ 131 | ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndtmsg)))) 132 | #endif 133 | #ifndef NDTA_PAYLOAD 134 | #define NDTA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ndtmsg)) 135 | #endif 136 | 137 | #endif /* __LIBNETLINK_H__ */ 138 | 139 | -------------------------------------------------------------------------------- /out-of-tree-3.16.x/Makefile: -------------------------------------------------------------------------------- 1 | ifneq ($(KERNELRELEASE),) 2 | # ugly and dirty hack to avoid patching system's kernel headers 3 | ccflags-y += "-DGREPROTO_NONSTD_EOIP=0x80" 4 | ccflags-y += "-DGREPROTO_NONSTD_MAX=0x81" 5 | ccflags-y += "-DGREPROTO_NONSTD_BASE=0x80" 6 | obj-m := eoip.o 7 | obj-m += gre.o 8 | else 9 | KDIR ?= /lib/modules/`uname -r`/build 10 | default: eoip.c gre.c gre.h 11 | @$(MAKE) -C $(KDIR) M=$$PWD 12 | eoip.c: ../kernel-patch/kernel-3.16.0-eoip.patch 13 | @patch -p3 < $< 14 | gre.c gre.h: ../kernel-patch/kernel-3.15.0-eoip-gre-demux.patch 15 | @if [ -f /lib/modules/`uname -r`/build/net/ipv4/gre.c ]; then echo found running kernel version of gre.c; cp /lib/modules/`uname -r`/build/net/ipv4/gre_demux.c gre_demux.c; else echo using 3.16.0 version of gre_demux.c; cp gre_demux-3.16.0.c gre_demux.c; fi 16 | @if [ -f /lib/modules/`uname -r`/build/include/net/gre.h ]; then echo found running kernel version of gre.h; cp /lib/modules/`uname -r`/build/include/net/gre.h gre.h; else echo using 3.16.0 version of gre.h; cp gre-3.16.0.h gre.h; fi 17 | @patch -p3 < $< 18 | @cp gre_demux.c gre.c 19 | clean: 20 | @rm -f gre_demux.c gre.c gre.h eoip.c *.orig *.rej 21 | @$(MAKE) -C $(KDIR) M=$$PWD clean 22 | install modules_install: 23 | @$(MAKE) -C $(KDIR) M=$$PWD modules_install 24 | endif 25 | -------------------------------------------------------------------------------- /out-of-tree-3.16.x/gre-3.16.0.h: -------------------------------------------------------------------------------- 1 | #ifndef __LINUX_GRE_H 2 | #define __LINUX_GRE_H 3 | 4 | #include 5 | #include 6 | 7 | #define GREPROTO_CISCO 0 8 | #define GREPROTO_PPTP 1 9 | #define GREPROTO_MAX 2 10 | #define GRE_IP_PROTO_MAX 2 11 | 12 | struct gre_protocol { 13 | int (*handler)(struct sk_buff *skb); 14 | void (*err_handler)(struct sk_buff *skb, u32 info); 15 | }; 16 | 17 | struct gre_base_hdr { 18 | __be16 flags; 19 | __be16 protocol; 20 | }; 21 | #define GRE_HEADER_SECTION 4 22 | 23 | int gre_add_protocol(const struct gre_protocol *proto, u8 version); 24 | int gre_del_protocol(const struct gre_protocol *proto, u8 version); 25 | 26 | struct gre_cisco_protocol { 27 | int (*handler)(struct sk_buff *skb, const struct tnl_ptk_info *tpi); 28 | int (*err_handler)(struct sk_buff *skb, u32 info, 29 | const struct tnl_ptk_info *tpi); 30 | u8 priority; 31 | }; 32 | 33 | int gre_cisco_register(struct gre_cisco_protocol *proto); 34 | int gre_cisco_unregister(struct gre_cisco_protocol *proto); 35 | 36 | void gre_build_header(struct sk_buff *skb, const struct tnl_ptk_info *tpi, 37 | int hdr_len); 38 | 39 | static inline struct sk_buff *gre_handle_offloads(struct sk_buff *skb, 40 | bool csum) 41 | { 42 | return iptunnel_handle_offloads(skb, csum, 43 | csum ? SKB_GSO_GRE_CSUM : SKB_GSO_GRE); 44 | } 45 | 46 | 47 | static inline int ip_gre_calc_hlen(__be16 o_flags) 48 | { 49 | int addend = 4; 50 | 51 | if (o_flags&TUNNEL_CSUM) 52 | addend += 4; 53 | if (o_flags&TUNNEL_KEY) 54 | addend += 4; 55 | if (o_flags&TUNNEL_SEQ) 56 | addend += 4; 57 | return addend; 58 | } 59 | 60 | static inline __be16 gre_flags_to_tnl_flags(__be16 flags) 61 | { 62 | __be16 tflags = 0; 63 | 64 | if (flags & GRE_CSUM) 65 | tflags |= TUNNEL_CSUM; 66 | if (flags & GRE_ROUTING) 67 | tflags |= TUNNEL_ROUTING; 68 | if (flags & GRE_KEY) 69 | tflags |= TUNNEL_KEY; 70 | if (flags & GRE_SEQ) 71 | tflags |= TUNNEL_SEQ; 72 | if (flags & GRE_STRICT) 73 | tflags |= TUNNEL_STRICT; 74 | if (flags & GRE_REC) 75 | tflags |= TUNNEL_REC; 76 | if (flags & GRE_VERSION) 77 | tflags |= TUNNEL_VERSION; 78 | 79 | return tflags; 80 | } 81 | 82 | static inline __be16 tnl_flags_to_gre_flags(__be16 tflags) 83 | { 84 | __be16 flags = 0; 85 | 86 | if (tflags & TUNNEL_CSUM) 87 | flags |= GRE_CSUM; 88 | if (tflags & TUNNEL_ROUTING) 89 | flags |= GRE_ROUTING; 90 | if (tflags & TUNNEL_KEY) 91 | flags |= GRE_KEY; 92 | if (tflags & TUNNEL_SEQ) 93 | flags |= GRE_SEQ; 94 | if (tflags & TUNNEL_STRICT) 95 | flags |= GRE_STRICT; 96 | if (tflags & TUNNEL_REC) 97 | flags |= GRE_REC; 98 | if (tflags & TUNNEL_VERSION) 99 | flags |= GRE_VERSION; 100 | 101 | return flags; 102 | } 103 | 104 | #endif 105 | -------------------------------------------------------------------------------- /out-of-tree-3.16.x/gre_demux-3.16.0.c: -------------------------------------------------------------------------------- 1 | /* 2 | * GRE over IPv4 demultiplexer driver 3 | * 4 | * Authors: Dmitry Kozlov (xeb@mail.ru) 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 9 | * 2 of the License, or (at your option) any later version. 10 | * 11 | */ 12 | 13 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | static const struct gre_protocol __rcu *gre_proto[GREPROTO_MAX] __read_mostly; 34 | static struct gre_cisco_protocol __rcu *gre_cisco_proto_list[GRE_IP_PROTO_MAX]; 35 | 36 | int gre_add_protocol(const struct gre_protocol *proto, u8 version) 37 | { 38 | if (version >= GREPROTO_MAX) 39 | return -EINVAL; 40 | 41 | return (cmpxchg((const struct gre_protocol **)&gre_proto[version], NULL, proto) == NULL) ? 42 | 0 : -EBUSY; 43 | } 44 | EXPORT_SYMBOL_GPL(gre_add_protocol); 45 | 46 | int gre_del_protocol(const struct gre_protocol *proto, u8 version) 47 | { 48 | int ret; 49 | 50 | if (version >= GREPROTO_MAX) 51 | return -EINVAL; 52 | 53 | ret = (cmpxchg((const struct gre_protocol **)&gre_proto[version], proto, NULL) == proto) ? 54 | 0 : -EBUSY; 55 | 56 | if (ret) 57 | return ret; 58 | 59 | synchronize_rcu(); 60 | return 0; 61 | } 62 | EXPORT_SYMBOL_GPL(gre_del_protocol); 63 | 64 | void gre_build_header(struct sk_buff *skb, const struct tnl_ptk_info *tpi, 65 | int hdr_len) 66 | { 67 | struct gre_base_hdr *greh; 68 | 69 | skb_push(skb, hdr_len); 70 | 71 | skb_reset_transport_header(skb); 72 | greh = (struct gre_base_hdr *)skb->data; 73 | greh->flags = tnl_flags_to_gre_flags(tpi->flags); 74 | greh->protocol = tpi->proto; 75 | 76 | if (tpi->flags&(TUNNEL_KEY|TUNNEL_CSUM|TUNNEL_SEQ)) { 77 | __be32 *ptr = (__be32 *)(((u8 *)greh) + hdr_len - 4); 78 | 79 | if (tpi->flags&TUNNEL_SEQ) { 80 | *ptr = tpi->seq; 81 | ptr--; 82 | } 83 | if (tpi->flags&TUNNEL_KEY) { 84 | *ptr = tpi->key; 85 | ptr--; 86 | } 87 | if (tpi->flags&TUNNEL_CSUM && 88 | !(skb_shinfo(skb)->gso_type & 89 | (SKB_GSO_GRE|SKB_GSO_GRE_CSUM))) { 90 | *ptr = 0; 91 | *(__sum16 *)ptr = csum_fold(skb_checksum(skb, 0, 92 | skb->len, 0)); 93 | } 94 | } 95 | } 96 | EXPORT_SYMBOL_GPL(gre_build_header); 97 | 98 | static int parse_gre_header(struct sk_buff *skb, struct tnl_ptk_info *tpi, 99 | bool *csum_err) 100 | { 101 | unsigned int ip_hlen = ip_hdrlen(skb); 102 | const struct gre_base_hdr *greh; 103 | __be32 *options; 104 | int hdr_len; 105 | 106 | if (unlikely(!pskb_may_pull(skb, sizeof(struct gre_base_hdr)))) 107 | return -EINVAL; 108 | 109 | greh = (struct gre_base_hdr *)(skb_network_header(skb) + ip_hlen); 110 | if (unlikely(greh->flags & (GRE_VERSION | GRE_ROUTING))) 111 | return -EINVAL; 112 | 113 | tpi->flags = gre_flags_to_tnl_flags(greh->flags); 114 | hdr_len = ip_gre_calc_hlen(tpi->flags); 115 | 116 | if (!pskb_may_pull(skb, hdr_len)) 117 | return -EINVAL; 118 | 119 | greh = (struct gre_base_hdr *)(skb_network_header(skb) + ip_hlen); 120 | tpi->proto = greh->protocol; 121 | 122 | options = (__be32 *)(greh + 1); 123 | if (greh->flags & GRE_CSUM) { 124 | if (skb_checksum_simple_validate(skb)) { 125 | *csum_err = true; 126 | return -EINVAL; 127 | } 128 | options++; 129 | } 130 | 131 | if (greh->flags & GRE_KEY) { 132 | tpi->key = *options; 133 | options++; 134 | } else 135 | tpi->key = 0; 136 | 137 | if (unlikely(greh->flags & GRE_SEQ)) { 138 | tpi->seq = *options; 139 | options++; 140 | } else 141 | tpi->seq = 0; 142 | 143 | /* WCCP version 1 and 2 protocol decoding. 144 | * - Change protocol to IP 145 | * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header 146 | */ 147 | if (greh->flags == 0 && tpi->proto == htons(ETH_P_WCCP)) { 148 | tpi->proto = htons(ETH_P_IP); 149 | if ((*(u8 *)options & 0xF0) != 0x40) { 150 | hdr_len += 4; 151 | if (!pskb_may_pull(skb, hdr_len)) 152 | return -EINVAL; 153 | } 154 | } 155 | 156 | return iptunnel_pull_header(skb, hdr_len, tpi->proto); 157 | } 158 | 159 | static int gre_cisco_rcv(struct sk_buff *skb) 160 | { 161 | struct tnl_ptk_info tpi; 162 | int i; 163 | bool csum_err = false; 164 | 165 | #ifdef CONFIG_NET_IPGRE_BROADCAST 166 | if (ipv4_is_multicast(ip_hdr(skb)->daddr)) { 167 | /* Looped back packet, drop it! */ 168 | if (rt_is_output_route(skb_rtable(skb))) 169 | goto drop; 170 | } 171 | #endif 172 | 173 | if (parse_gre_header(skb, &tpi, &csum_err) < 0) 174 | goto drop; 175 | 176 | rcu_read_lock(); 177 | for (i = 0; i < GRE_IP_PROTO_MAX; i++) { 178 | struct gre_cisco_protocol *proto; 179 | int ret; 180 | 181 | proto = rcu_dereference(gre_cisco_proto_list[i]); 182 | if (!proto) 183 | continue; 184 | ret = proto->handler(skb, &tpi); 185 | if (ret == PACKET_RCVD) { 186 | rcu_read_unlock(); 187 | return 0; 188 | } 189 | } 190 | rcu_read_unlock(); 191 | 192 | icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); 193 | drop: 194 | kfree_skb(skb); 195 | return 0; 196 | } 197 | 198 | static void gre_cisco_err(struct sk_buff *skb, u32 info) 199 | { 200 | /* All the routers (except for Linux) return only 201 | * 8 bytes of packet payload. It means, that precise relaying of 202 | * ICMP in the real Internet is absolutely infeasible. 203 | * 204 | * Moreover, Cisco "wise men" put GRE key to the third word 205 | * in GRE header. It makes impossible maintaining even soft 206 | * state for keyed 207 | * GRE tunnels with enabled checksum. Tell them "thank you". 208 | * 209 | * Well, I wonder, rfc1812 was written by Cisco employee, 210 | * what the hell these idiots break standards established 211 | * by themselves??? 212 | */ 213 | 214 | const int type = icmp_hdr(skb)->type; 215 | const int code = icmp_hdr(skb)->code; 216 | struct tnl_ptk_info tpi; 217 | bool csum_err = false; 218 | int i; 219 | 220 | if (parse_gre_header(skb, &tpi, &csum_err)) { 221 | if (!csum_err) /* ignore csum errors. */ 222 | return; 223 | } 224 | 225 | if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) { 226 | ipv4_update_pmtu(skb, dev_net(skb->dev), info, 227 | skb->dev->ifindex, 0, IPPROTO_GRE, 0); 228 | return; 229 | } 230 | if (type == ICMP_REDIRECT) { 231 | ipv4_redirect(skb, dev_net(skb->dev), skb->dev->ifindex, 0, 232 | IPPROTO_GRE, 0); 233 | return; 234 | } 235 | 236 | rcu_read_lock(); 237 | for (i = 0; i < GRE_IP_PROTO_MAX; i++) { 238 | struct gre_cisco_protocol *proto; 239 | 240 | proto = rcu_dereference(gre_cisco_proto_list[i]); 241 | if (!proto) 242 | continue; 243 | 244 | if (proto->err_handler(skb, info, &tpi) == PACKET_RCVD) 245 | goto out; 246 | 247 | } 248 | out: 249 | rcu_read_unlock(); 250 | } 251 | 252 | static int gre_rcv(struct sk_buff *skb) 253 | { 254 | const struct gre_protocol *proto; 255 | u8 ver; 256 | int ret; 257 | 258 | if (!pskb_may_pull(skb, 12)) 259 | goto drop; 260 | 261 | ver = skb->data[1]&0x7f; 262 | if (ver >= GREPROTO_MAX) 263 | goto drop; 264 | 265 | rcu_read_lock(); 266 | proto = rcu_dereference(gre_proto[ver]); 267 | if (!proto || !proto->handler) 268 | goto drop_unlock; 269 | ret = proto->handler(skb); 270 | rcu_read_unlock(); 271 | return ret; 272 | 273 | drop_unlock: 274 | rcu_read_unlock(); 275 | drop: 276 | kfree_skb(skb); 277 | return NET_RX_DROP; 278 | } 279 | 280 | static void gre_err(struct sk_buff *skb, u32 info) 281 | { 282 | const struct gre_protocol *proto; 283 | const struct iphdr *iph = (const struct iphdr *)skb->data; 284 | u8 ver = skb->data[(iph->ihl<<2) + 1]&0x7f; 285 | 286 | if (ver >= GREPROTO_MAX) 287 | return; 288 | 289 | rcu_read_lock(); 290 | proto = rcu_dereference(gre_proto[ver]); 291 | if (proto && proto->err_handler) 292 | proto->err_handler(skb, info); 293 | rcu_read_unlock(); 294 | } 295 | 296 | static const struct net_protocol net_gre_protocol = { 297 | .handler = gre_rcv, 298 | .err_handler = gre_err, 299 | .netns_ok = 1, 300 | }; 301 | 302 | static const struct gre_protocol ipgre_protocol = { 303 | .handler = gre_cisco_rcv, 304 | .err_handler = gre_cisco_err, 305 | }; 306 | 307 | int gre_cisco_register(struct gre_cisco_protocol *newp) 308 | { 309 | struct gre_cisco_protocol **proto = (struct gre_cisco_protocol **) 310 | &gre_cisco_proto_list[newp->priority]; 311 | 312 | return (cmpxchg(proto, NULL, newp) == NULL) ? 0 : -EBUSY; 313 | } 314 | EXPORT_SYMBOL_GPL(gre_cisco_register); 315 | 316 | int gre_cisco_unregister(struct gre_cisco_protocol *del_proto) 317 | { 318 | struct gre_cisco_protocol **proto = (struct gre_cisco_protocol **) 319 | &gre_cisco_proto_list[del_proto->priority]; 320 | int ret; 321 | 322 | ret = (cmpxchg(proto, del_proto, NULL) == del_proto) ? 0 : -EINVAL; 323 | 324 | if (ret) 325 | return ret; 326 | 327 | synchronize_net(); 328 | return 0; 329 | } 330 | EXPORT_SYMBOL_GPL(gre_cisco_unregister); 331 | 332 | static int __init gre_init(void) 333 | { 334 | pr_info("GRE over IPv4 demultiplexor driver\n"); 335 | 336 | if (inet_add_protocol(&net_gre_protocol, IPPROTO_GRE) < 0) { 337 | pr_err("can't add protocol\n"); 338 | goto err; 339 | } 340 | 341 | if (gre_add_protocol(&ipgre_protocol, GREPROTO_CISCO) < 0) { 342 | pr_info("%s: can't add ipgre handler\n", __func__); 343 | goto err_gre; 344 | } 345 | 346 | return 0; 347 | err_gre: 348 | inet_del_protocol(&net_gre_protocol, IPPROTO_GRE); 349 | err: 350 | return -EAGAIN; 351 | } 352 | 353 | static void __exit gre_exit(void) 354 | { 355 | gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO); 356 | inet_del_protocol(&net_gre_protocol, IPPROTO_GRE); 357 | } 358 | 359 | module_init(gre_init); 360 | module_exit(gre_exit); 361 | 362 | MODULE_DESCRIPTION("GRE over IPv4 demultiplexer driver"); 363 | MODULE_AUTHOR("D. Kozlov (xeb@mail.ru)"); 364 | MODULE_LICENSE("GPL"); 365 | -------------------------------------------------------------------------------- /out-of-tree-3.2.x/Makefile: -------------------------------------------------------------------------------- 1 | ifneq ($(KERNELRELEASE),) 2 | # ugly and dirty hack to avoid patching system's kernel headers 3 | ccflags-y += "-DGREPROTO_NONSTD_EOIP=0x80" 4 | ccflags-y += "-DGREPROTO_NONSTD_MAX=0x81" 5 | ccflags-y += "-DGREPROTO_NONSTD_BASE=0x80" 6 | obj-m := eoip.o 7 | obj-m += gre.o 8 | else 9 | KDIR ?= /lib/modules/`uname -r`/build 10 | default: eoip.c gre.c gre.h 11 | @$(MAKE) -C $(KDIR) M=$$PWD 12 | eoip.c: ../kernel-patch/kernel-3.2.44-eoip.patch 13 | @patch -p3 < $< 14 | gre.c gre.h: ../kernel-patch/kernel-3.2.44-eoip-gre-demux.patch 15 | @if [ -f /lib/modules/`uname -r`/build/net/ipv4/gre.c ]; then echo found running kernel version of gre.c; cp /lib/modules/`uname -r`/build/net/ipv4/gre.c gre.c; else echo using 3.2.44 version of gre.c; cp gre-3.2.44.c gre.c; fi 16 | @if [ -f /lib/modules/`uname -r`/build/include/net/gre.h ]; then echo found running kernel version of gre.h; cp /lib/modules/`uname -r`/build/include/net/gre.h gre.h; else echo using 3.2.44 version of gre.h; cp gre-3.2.44.h gre.h; fi 17 | @patch -p3 < $< 18 | clean: 19 | @rm -f gre.c gre.h eoip.c 20 | @$(MAKE) -C $(KDIR) M=$$PWD clean 21 | install modules_install: 22 | @$(MAKE) -C $(KDIR) M=$$PWD modules_install 23 | endif 24 | -------------------------------------------------------------------------------- /out-of-tree-3.2.x/gre-3.2.44.c: -------------------------------------------------------------------------------- 1 | /* 2 | * GRE over IPv4 demultiplexer driver 3 | * 4 | * Authors: Dmitry Kozlov (xeb@mail.ru) 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 9 | * 2 of the License, or (at your option) any later version. 10 | * 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | 25 | static const struct gre_protocol __rcu *gre_proto[GREPROTO_MAX] __read_mostly; 26 | static DEFINE_SPINLOCK(gre_proto_lock); 27 | 28 | int gre_add_protocol(const struct gre_protocol *proto, u8 version) 29 | { 30 | if (version >= GREPROTO_MAX) 31 | goto err_out; 32 | 33 | spin_lock(&gre_proto_lock); 34 | if (gre_proto[version]) 35 | goto err_out_unlock; 36 | 37 | RCU_INIT_POINTER(gre_proto[version], proto); 38 | spin_unlock(&gre_proto_lock); 39 | return 0; 40 | 41 | err_out_unlock: 42 | spin_unlock(&gre_proto_lock); 43 | err_out: 44 | return -1; 45 | } 46 | EXPORT_SYMBOL_GPL(gre_add_protocol); 47 | 48 | int gre_del_protocol(const struct gre_protocol *proto, u8 version) 49 | { 50 | if (version >= GREPROTO_MAX) 51 | goto err_out; 52 | 53 | spin_lock(&gre_proto_lock); 54 | if (rcu_dereference_protected(gre_proto[version], 55 | lockdep_is_held(&gre_proto_lock)) != proto) 56 | goto err_out_unlock; 57 | RCU_INIT_POINTER(gre_proto[version], NULL); 58 | spin_unlock(&gre_proto_lock); 59 | synchronize_rcu(); 60 | return 0; 61 | 62 | err_out_unlock: 63 | spin_unlock(&gre_proto_lock); 64 | err_out: 65 | return -1; 66 | } 67 | EXPORT_SYMBOL_GPL(gre_del_protocol); 68 | 69 | static int gre_rcv(struct sk_buff *skb) 70 | { 71 | const struct gre_protocol *proto; 72 | u8 ver; 73 | int ret; 74 | 75 | if (!pskb_may_pull(skb, 12)) 76 | goto drop; 77 | 78 | ver = skb->data[1]&0x7f; 79 | if (ver >= GREPROTO_MAX) 80 | goto drop; 81 | 82 | rcu_read_lock(); 83 | proto = rcu_dereference(gre_proto[ver]); 84 | if (!proto || !proto->handler) 85 | goto drop_unlock; 86 | ret = proto->handler(skb); 87 | rcu_read_unlock(); 88 | return ret; 89 | 90 | drop_unlock: 91 | rcu_read_unlock(); 92 | drop: 93 | kfree_skb(skb); 94 | return NET_RX_DROP; 95 | } 96 | 97 | static void gre_err(struct sk_buff *skb, u32 info) 98 | { 99 | const struct gre_protocol *proto; 100 | const struct iphdr *iph = (const struct iphdr *)skb->data; 101 | u8 ver = skb->data[(iph->ihl<<2) + 1]&0x7f; 102 | 103 | if (ver >= GREPROTO_MAX) 104 | return; 105 | 106 | rcu_read_lock(); 107 | proto = rcu_dereference(gre_proto[ver]); 108 | if (proto && proto->err_handler) 109 | proto->err_handler(skb, info); 110 | rcu_read_unlock(); 111 | } 112 | 113 | static const struct net_protocol net_gre_protocol = { 114 | .handler = gre_rcv, 115 | .err_handler = gre_err, 116 | .netns_ok = 1, 117 | }; 118 | 119 | static int __init gre_init(void) 120 | { 121 | pr_info("GRE over IPv4 demultiplexor driver"); 122 | 123 | if (inet_add_protocol(&net_gre_protocol, IPPROTO_GRE) < 0) { 124 | pr_err("gre: can't add protocol\n"); 125 | return -EAGAIN; 126 | } 127 | 128 | return 0; 129 | } 130 | 131 | static void __exit gre_exit(void) 132 | { 133 | inet_del_protocol(&net_gre_protocol, IPPROTO_GRE); 134 | } 135 | 136 | module_init(gre_init); 137 | module_exit(gre_exit); 138 | 139 | MODULE_DESCRIPTION("GRE over IPv4 demultiplexer driver"); 140 | MODULE_AUTHOR("D. Kozlov (xeb@mail.ru)"); 141 | MODULE_LICENSE("GPL"); 142 | 143 | -------------------------------------------------------------------------------- /out-of-tree-3.2.x/gre-3.2.44.h: -------------------------------------------------------------------------------- 1 | #ifndef __LINUX_GRE_H 2 | #define __LINUX_GRE_H 3 | 4 | #include 5 | 6 | #define GREPROTO_CISCO 0 7 | #define GREPROTO_PPTP 1 8 | #define GREPROTO_MAX 2 9 | 10 | struct gre_protocol { 11 | int (*handler)(struct sk_buff *skb); 12 | void (*err_handler)(struct sk_buff *skb, u32 info); 13 | }; 14 | 15 | int gre_add_protocol(const struct gre_protocol *proto, u8 version); 16 | int gre_del_protocol(const struct gre_protocol *proto, u8 version); 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /out-of-tree-4.15.x/Makefile: -------------------------------------------------------------------------------- 1 | ifneq ($(KERNELRELEASE),) 2 | # ugly and dirty hack to avoid patching system's kernel headers 3 | ccflags-y += "-DGREPROTO_NONSTD_EOIP=0x80" 4 | ccflags-y += "-DGREPROTO_NONSTD_MAX=0x81" 5 | ccflags-y += "-DGREPROTO_NONSTD_BASE=0x80" 6 | obj-m := eoip.o 7 | obj-m += gre.o 8 | else 9 | KDIR ?= /lib/modules/`uname -r`/build 10 | default: eoip.c gre.c gre.h 11 | @$(MAKE) -C $(KDIR) M=$$PWD 12 | eoip.c: ../kernel-patch/kernel-4.15.0-eoip.patch 13 | @patch -p3 < $< 14 | gre.c gre.h: ../kernel-patch/kernel-4.15.0-eoip-gre-demux.patch 15 | @if [ -f /lib/modules/`uname -r`/build/net/ipv4/gre.c ]; then echo found running kernel version of gre.c; cp /lib/modules/`uname -r`/build/net/ipv4/gre_demux.c gre_demux.c; else echo using 4.15.0 version of gre_demux.c; cp gre_demux-4.15.0.c gre_demux.c; fi 16 | @if [ -f /lib/modules/`uname -r`/build/include/net/gre.h ]; then echo found running kernel version of gre.h; cp /lib/modules/`uname -r`/build/include/net/gre.h gre.h; else echo using 4.15.0 version of gre.h; cp gre-4.15.0.h gre.h; fi 17 | @patch -p3 < $< 18 | @cp gre_demux.c gre.c 19 | clean: 20 | @rm -f gre_demux.c gre.c gre.h eoip.c *.orig *.rej 21 | @$(MAKE) -C $(KDIR) M=$$PWD clean 22 | install modules_install: 23 | @$(MAKE) -C $(KDIR) M=$$PWD modules_install 24 | endif 25 | -------------------------------------------------------------------------------- /out-of-tree-4.15.x/gre-4.15.0.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | #ifndef __LINUX_GRE_H 3 | #define __LINUX_GRE_H 4 | 5 | #include 6 | #include 7 | 8 | struct gre_base_hdr { 9 | __be16 flags; 10 | __be16 protocol; 11 | } __packed; 12 | 13 | struct gre_full_hdr { 14 | struct gre_base_hdr fixed_header; 15 | __be16 csum; 16 | __be16 reserved1; 17 | __be32 key; 18 | __be32 seq; 19 | } __packed; 20 | #define GRE_HEADER_SECTION 4 21 | 22 | #define GREPROTO_CISCO 0 23 | #define GREPROTO_PPTP 1 24 | #define GREPROTO_MAX 2 25 | #define GRE_IP_PROTO_MAX 2 26 | 27 | struct gre_protocol { 28 | int (*handler)(struct sk_buff *skb); 29 | void (*err_handler)(struct sk_buff *skb, u32 info); 30 | }; 31 | 32 | int gre_add_protocol(const struct gre_protocol *proto, u8 version); 33 | int gre_del_protocol(const struct gre_protocol *proto, u8 version); 34 | 35 | struct net_device *gretap_fb_dev_create(struct net *net, const char *name, 36 | u8 name_assign_type); 37 | int gre_parse_header(struct sk_buff *skb, struct tnl_ptk_info *tpi, 38 | bool *csum_err, __be16 proto, int nhs); 39 | 40 | static inline int gre_calc_hlen(__be16 o_flags) 41 | { 42 | int addend = 4; 43 | 44 | if (o_flags & TUNNEL_CSUM) 45 | addend += 4; 46 | if (o_flags & TUNNEL_KEY) 47 | addend += 4; 48 | if (o_flags & TUNNEL_SEQ) 49 | addend += 4; 50 | return addend; 51 | } 52 | 53 | static inline __be16 gre_flags_to_tnl_flags(__be16 flags) 54 | { 55 | __be16 tflags = 0; 56 | 57 | if (flags & GRE_CSUM) 58 | tflags |= TUNNEL_CSUM; 59 | if (flags & GRE_ROUTING) 60 | tflags |= TUNNEL_ROUTING; 61 | if (flags & GRE_KEY) 62 | tflags |= TUNNEL_KEY; 63 | if (flags & GRE_SEQ) 64 | tflags |= TUNNEL_SEQ; 65 | if (flags & GRE_STRICT) 66 | tflags |= TUNNEL_STRICT; 67 | if (flags & GRE_REC) 68 | tflags |= TUNNEL_REC; 69 | if (flags & GRE_VERSION) 70 | tflags |= TUNNEL_VERSION; 71 | 72 | return tflags; 73 | } 74 | 75 | static inline __be16 gre_tnl_flags_to_gre_flags(__be16 tflags) 76 | { 77 | __be16 flags = 0; 78 | 79 | if (tflags & TUNNEL_CSUM) 80 | flags |= GRE_CSUM; 81 | if (tflags & TUNNEL_ROUTING) 82 | flags |= GRE_ROUTING; 83 | if (tflags & TUNNEL_KEY) 84 | flags |= GRE_KEY; 85 | if (tflags & TUNNEL_SEQ) 86 | flags |= GRE_SEQ; 87 | if (tflags & TUNNEL_STRICT) 88 | flags |= GRE_STRICT; 89 | if (tflags & TUNNEL_REC) 90 | flags |= GRE_REC; 91 | if (tflags & TUNNEL_VERSION) 92 | flags |= GRE_VERSION; 93 | 94 | return flags; 95 | } 96 | 97 | static inline __sum16 gre_checksum(struct sk_buff *skb) 98 | { 99 | __wsum csum; 100 | 101 | if (skb->ip_summed == CHECKSUM_PARTIAL) 102 | csum = lco_csum(skb); 103 | else 104 | csum = skb_checksum(skb, 0, skb->len, 0); 105 | return csum_fold(csum); 106 | } 107 | 108 | static inline void gre_build_header(struct sk_buff *skb, int hdr_len, 109 | __be16 flags, __be16 proto, 110 | __be32 key, __be32 seq) 111 | { 112 | struct gre_base_hdr *greh; 113 | 114 | skb_push(skb, hdr_len); 115 | 116 | skb_set_inner_protocol(skb, proto); 117 | skb_reset_transport_header(skb); 118 | greh = (struct gre_base_hdr *)skb->data; 119 | greh->flags = gre_tnl_flags_to_gre_flags(flags); 120 | greh->protocol = proto; 121 | 122 | if (flags & (TUNNEL_KEY | TUNNEL_CSUM | TUNNEL_SEQ)) { 123 | __be32 *ptr = (__be32 *)(((u8 *)greh) + hdr_len - 4); 124 | 125 | if (flags & TUNNEL_SEQ) { 126 | *ptr = seq; 127 | ptr--; 128 | } 129 | if (flags & TUNNEL_KEY) { 130 | *ptr = key; 131 | ptr--; 132 | } 133 | if (flags & TUNNEL_CSUM && 134 | !(skb_shinfo(skb)->gso_type & 135 | (SKB_GSO_GRE | SKB_GSO_GRE_CSUM))) { 136 | *ptr = 0; 137 | *(__sum16 *)ptr = gre_checksum(skb); 138 | } 139 | } 140 | } 141 | 142 | #endif 143 | -------------------------------------------------------------------------------- /out-of-tree-4.15.x/gre_demux-4.15.0.c: -------------------------------------------------------------------------------- 1 | /* 2 | * GRE over IPv4 demultiplexer driver 3 | * 4 | * Authors: Dmitry Kozlov (xeb@mail.ru) 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 9 | * 2 of the License, or (at your option) any later version. 10 | * 11 | */ 12 | 13 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | static const struct gre_protocol __rcu *gre_proto[GREPROTO_MAX] __read_mostly; 34 | 35 | int gre_add_protocol(const struct gre_protocol *proto, u8 version) 36 | { 37 | if (version >= GREPROTO_MAX) 38 | return -EINVAL; 39 | 40 | return (cmpxchg((const struct gre_protocol **)&gre_proto[version], NULL, proto) == NULL) ? 41 | 0 : -EBUSY; 42 | } 43 | EXPORT_SYMBOL_GPL(gre_add_protocol); 44 | 45 | int gre_del_protocol(const struct gre_protocol *proto, u8 version) 46 | { 47 | int ret; 48 | 49 | if (version >= GREPROTO_MAX) 50 | return -EINVAL; 51 | 52 | ret = (cmpxchg((const struct gre_protocol **)&gre_proto[version], proto, NULL) == proto) ? 53 | 0 : -EBUSY; 54 | 55 | if (ret) 56 | return ret; 57 | 58 | synchronize_rcu(); 59 | return 0; 60 | } 61 | EXPORT_SYMBOL_GPL(gre_del_protocol); 62 | 63 | /* Fills in tpi and returns header length to be pulled. */ 64 | int gre_parse_header(struct sk_buff *skb, struct tnl_ptk_info *tpi, 65 | bool *csum_err, __be16 proto, int nhs) 66 | { 67 | const struct gre_base_hdr *greh; 68 | __be32 *options; 69 | int hdr_len; 70 | 71 | if (unlikely(!pskb_may_pull(skb, nhs + sizeof(struct gre_base_hdr)))) 72 | return -EINVAL; 73 | 74 | greh = (struct gre_base_hdr *)(skb->data + nhs); 75 | if (unlikely(greh->flags & (GRE_VERSION | GRE_ROUTING))) 76 | return -EINVAL; 77 | 78 | tpi->flags = gre_flags_to_tnl_flags(greh->flags); 79 | hdr_len = gre_calc_hlen(tpi->flags); 80 | 81 | if (!pskb_may_pull(skb, nhs + hdr_len)) 82 | return -EINVAL; 83 | 84 | greh = (struct gre_base_hdr *)(skb->data + nhs); 85 | tpi->proto = greh->protocol; 86 | 87 | options = (__be32 *)(greh + 1); 88 | if (greh->flags & GRE_CSUM) { 89 | if (skb_checksum_simple_validate(skb)) { 90 | *csum_err = true; 91 | return -EINVAL; 92 | } 93 | 94 | skb_checksum_try_convert(skb, IPPROTO_GRE, 0, 95 | null_compute_pseudo); 96 | options++; 97 | } 98 | 99 | if (greh->flags & GRE_KEY) { 100 | tpi->key = *options; 101 | options++; 102 | } else { 103 | tpi->key = 0; 104 | } 105 | if (unlikely(greh->flags & GRE_SEQ)) { 106 | tpi->seq = *options; 107 | options++; 108 | } else { 109 | tpi->seq = 0; 110 | } 111 | /* WCCP version 1 and 2 protocol decoding. 112 | * - Change protocol to IPv4/IPv6 113 | * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header 114 | */ 115 | if (greh->flags == 0 && tpi->proto == htons(ETH_P_WCCP)) { 116 | tpi->proto = proto; 117 | if ((*(u8 *)options & 0xF0) != 0x40) 118 | hdr_len += 4; 119 | } 120 | tpi->hdr_len = hdr_len; 121 | return hdr_len; 122 | } 123 | EXPORT_SYMBOL(gre_parse_header); 124 | 125 | static int gre_rcv(struct sk_buff *skb) 126 | { 127 | const struct gre_protocol *proto; 128 | u8 ver; 129 | int ret; 130 | 131 | if (!pskb_may_pull(skb, 12)) 132 | goto drop; 133 | 134 | ver = skb->data[1]&0x7f; 135 | if (ver >= GREPROTO_MAX) 136 | goto drop; 137 | 138 | rcu_read_lock(); 139 | proto = rcu_dereference(gre_proto[ver]); 140 | if (!proto || !proto->handler) 141 | goto drop_unlock; 142 | ret = proto->handler(skb); 143 | rcu_read_unlock(); 144 | return ret; 145 | 146 | drop_unlock: 147 | rcu_read_unlock(); 148 | drop: 149 | kfree_skb(skb); 150 | return NET_RX_DROP; 151 | } 152 | 153 | static void gre_err(struct sk_buff *skb, u32 info) 154 | { 155 | const struct gre_protocol *proto; 156 | const struct iphdr *iph = (const struct iphdr *)skb->data; 157 | u8 ver = skb->data[(iph->ihl<<2) + 1]&0x7f; 158 | 159 | if (ver >= GREPROTO_MAX) 160 | return; 161 | 162 | rcu_read_lock(); 163 | proto = rcu_dereference(gre_proto[ver]); 164 | if (proto && proto->err_handler) 165 | proto->err_handler(skb, info); 166 | rcu_read_unlock(); 167 | } 168 | 169 | static const struct net_protocol net_gre_protocol = { 170 | .handler = gre_rcv, 171 | .err_handler = gre_err, 172 | .netns_ok = 1, 173 | }; 174 | 175 | static int __init gre_init(void) 176 | { 177 | pr_info("GRE over IPv4 demultiplexor driver\n"); 178 | 179 | if (inet_add_protocol(&net_gre_protocol, IPPROTO_GRE) < 0) { 180 | pr_err("can't add protocol\n"); 181 | return -EAGAIN; 182 | } 183 | return 0; 184 | } 185 | 186 | static void __exit gre_exit(void) 187 | { 188 | inet_del_protocol(&net_gre_protocol, IPPROTO_GRE); 189 | } 190 | 191 | module_init(gre_init); 192 | module_exit(gre_exit); 193 | 194 | MODULE_DESCRIPTION("GRE over IPv4 demultiplexer driver"); 195 | MODULE_AUTHOR("D. Kozlov (xeb@mail.ru)"); 196 | MODULE_LICENSE("GPL"); 197 | -------------------------------------------------------------------------------- /out-of-tree-4.19.x/Makefile: -------------------------------------------------------------------------------- 1 | ifneq ($(KERNELRELEASE),) 2 | # ugly and dirty hack to avoid patching system's kernel headers 3 | ccflags-y += "-DGREPROTO_NONSTD_EOIP=0x80" 4 | ccflags-y += "-DGREPROTO_NONSTD_MAX=0x81" 5 | ccflags-y += "-DGREPROTO_NONSTD_BASE=0x80" 6 | obj-m := eoip.o 7 | obj-m += gre.o 8 | else 9 | KDIR ?= /lib/modules/`uname -r`/build 10 | default: eoip.c gre.c gre.h 11 | @$(MAKE) -C $(KDIR) M=$$PWD 12 | eoip.c: ../kernel-patch/kernel-4.19.0-eoip.patch 13 | @patch -p3 < $< 14 | gre.c gre.h: ../kernel-patch/kernel-4.19.0-eoip-gre-demux.patch 15 | @if [ -f /lib/modules/`uname -r`/build/net/ipv4/gre.c ]; then echo found running kernel version of gre.c; cp /lib/modules/`uname -r`/build/net/ipv4/gre_demux.c gre_demux.c; else echo using 4.19.0 version of gre_demux.c; cp gre_demux-4.19.0.c gre_demux.c; fi 16 | @if [ -f /lib/modules/`uname -r`/build/include/net/gre.h ]; then echo found running kernel version of gre.h; cp /lib/modules/`uname -r`/build/include/net/gre.h gre.h; else echo using 4.19.0 version of gre.h; cp gre-4.19.0.h gre.h; fi 17 | @patch -p3 < $< 18 | @cp gre_demux.c gre.c 19 | clean: 20 | @rm -f gre_demux.c gre.c gre.h eoip.c *.orig *.rej 21 | @$(MAKE) -C $(KDIR) M=$$PWD clean 22 | install modules_install: 23 | @$(MAKE) -C $(KDIR) M=$$PWD modules_install 24 | endif 25 | -------------------------------------------------------------------------------- /out-of-tree-4.19.x/gre-4.19.0.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | #ifndef __LINUX_GRE_H 3 | #define __LINUX_GRE_H 4 | 5 | #include 6 | #include 7 | 8 | struct gre_base_hdr { 9 | __be16 flags; 10 | __be16 protocol; 11 | } __packed; 12 | 13 | struct gre_full_hdr { 14 | struct gre_base_hdr fixed_header; 15 | __be16 csum; 16 | __be16 reserved1; 17 | __be32 key; 18 | __be32 seq; 19 | } __packed; 20 | #define GRE_HEADER_SECTION 4 21 | 22 | #define GREPROTO_CISCO 0 23 | #define GREPROTO_PPTP 1 24 | #define GREPROTO_MAX 2 25 | #define GRE_IP_PROTO_MAX 2 26 | 27 | struct gre_protocol { 28 | int (*handler)(struct sk_buff *skb); 29 | void (*err_handler)(struct sk_buff *skb, u32 info); 30 | }; 31 | 32 | int gre_add_protocol(const struct gre_protocol *proto, u8 version); 33 | int gre_del_protocol(const struct gre_protocol *proto, u8 version); 34 | 35 | struct net_device *gretap_fb_dev_create(struct net *net, const char *name, 36 | u8 name_assign_type); 37 | int gre_parse_header(struct sk_buff *skb, struct tnl_ptk_info *tpi, 38 | bool *csum_err, __be16 proto, int nhs); 39 | 40 | bool is_gretap_dev(const struct net_device *dev); 41 | bool is_ip6gretap_dev(const struct net_device *dev); 42 | 43 | static inline int gre_calc_hlen(__be16 o_flags) 44 | { 45 | int addend = 4; 46 | 47 | if (o_flags & TUNNEL_CSUM) 48 | addend += 4; 49 | if (o_flags & TUNNEL_KEY) 50 | addend += 4; 51 | if (o_flags & TUNNEL_SEQ) 52 | addend += 4; 53 | return addend; 54 | } 55 | 56 | static inline __be16 gre_flags_to_tnl_flags(__be16 flags) 57 | { 58 | __be16 tflags = 0; 59 | 60 | if (flags & GRE_CSUM) 61 | tflags |= TUNNEL_CSUM; 62 | if (flags & GRE_ROUTING) 63 | tflags |= TUNNEL_ROUTING; 64 | if (flags & GRE_KEY) 65 | tflags |= TUNNEL_KEY; 66 | if (flags & GRE_SEQ) 67 | tflags |= TUNNEL_SEQ; 68 | if (flags & GRE_STRICT) 69 | tflags |= TUNNEL_STRICT; 70 | if (flags & GRE_REC) 71 | tflags |= TUNNEL_REC; 72 | if (flags & GRE_VERSION) 73 | tflags |= TUNNEL_VERSION; 74 | 75 | return tflags; 76 | } 77 | 78 | static inline __be16 gre_tnl_flags_to_gre_flags(__be16 tflags) 79 | { 80 | __be16 flags = 0; 81 | 82 | if (tflags & TUNNEL_CSUM) 83 | flags |= GRE_CSUM; 84 | if (tflags & TUNNEL_ROUTING) 85 | flags |= GRE_ROUTING; 86 | if (tflags & TUNNEL_KEY) 87 | flags |= GRE_KEY; 88 | if (tflags & TUNNEL_SEQ) 89 | flags |= GRE_SEQ; 90 | if (tflags & TUNNEL_STRICT) 91 | flags |= GRE_STRICT; 92 | if (tflags & TUNNEL_REC) 93 | flags |= GRE_REC; 94 | if (tflags & TUNNEL_VERSION) 95 | flags |= GRE_VERSION; 96 | 97 | return flags; 98 | } 99 | 100 | static inline __sum16 gre_checksum(struct sk_buff *skb) 101 | { 102 | __wsum csum; 103 | 104 | if (skb->ip_summed == CHECKSUM_PARTIAL) 105 | csum = lco_csum(skb); 106 | else 107 | csum = skb_checksum(skb, 0, skb->len, 0); 108 | return csum_fold(csum); 109 | } 110 | 111 | static inline void gre_build_header(struct sk_buff *skb, int hdr_len, 112 | __be16 flags, __be16 proto, 113 | __be32 key, __be32 seq) 114 | { 115 | struct gre_base_hdr *greh; 116 | 117 | skb_push(skb, hdr_len); 118 | 119 | skb_set_inner_protocol(skb, proto); 120 | skb_reset_transport_header(skb); 121 | greh = (struct gre_base_hdr *)skb->data; 122 | greh->flags = gre_tnl_flags_to_gre_flags(flags); 123 | greh->protocol = proto; 124 | 125 | if (flags & (TUNNEL_KEY | TUNNEL_CSUM | TUNNEL_SEQ)) { 126 | __be32 *ptr = (__be32 *)(((u8 *)greh) + hdr_len - 4); 127 | 128 | if (flags & TUNNEL_SEQ) { 129 | *ptr = seq; 130 | ptr--; 131 | } 132 | if (flags & TUNNEL_KEY) { 133 | *ptr = key; 134 | ptr--; 135 | } 136 | if (flags & TUNNEL_CSUM && 137 | !(skb_shinfo(skb)->gso_type & 138 | (SKB_GSO_GRE | SKB_GSO_GRE_CSUM))) { 139 | *ptr = 0; 140 | *(__sum16 *)ptr = gre_checksum(skb); 141 | } 142 | } 143 | } 144 | 145 | #endif 146 | -------------------------------------------------------------------------------- /out-of-tree-4.19.x/gre_demux-4.19.0.c: -------------------------------------------------------------------------------- 1 | /* 2 | * GRE over IPv4 demultiplexer driver 3 | * 4 | * Authors: Dmitry Kozlov (xeb@mail.ru) 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 9 | * 2 of the License, or (at your option) any later version. 10 | * 11 | */ 12 | 13 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | #include 33 | 34 | static const struct gre_protocol __rcu *gre_proto[GREPROTO_MAX] __read_mostly; 35 | 36 | int gre_add_protocol(const struct gre_protocol *proto, u8 version) 37 | { 38 | if (version >= GREPROTO_MAX) 39 | return -EINVAL; 40 | 41 | return (cmpxchg((const struct gre_protocol **)&gre_proto[version], NULL, proto) == NULL) ? 42 | 0 : -EBUSY; 43 | } 44 | EXPORT_SYMBOL_GPL(gre_add_protocol); 45 | 46 | int gre_del_protocol(const struct gre_protocol *proto, u8 version) 47 | { 48 | int ret; 49 | 50 | if (version >= GREPROTO_MAX) 51 | return -EINVAL; 52 | 53 | ret = (cmpxchg((const struct gre_protocol **)&gre_proto[version], proto, NULL) == proto) ? 54 | 0 : -EBUSY; 55 | 56 | if (ret) 57 | return ret; 58 | 59 | synchronize_rcu(); 60 | return 0; 61 | } 62 | EXPORT_SYMBOL_GPL(gre_del_protocol); 63 | 64 | /* Fills in tpi and returns header length to be pulled. */ 65 | int gre_parse_header(struct sk_buff *skb, struct tnl_ptk_info *tpi, 66 | bool *csum_err, __be16 proto, int nhs) 67 | { 68 | const struct gre_base_hdr *greh; 69 | __be32 *options; 70 | int hdr_len; 71 | 72 | if (unlikely(!pskb_may_pull(skb, nhs + sizeof(struct gre_base_hdr)))) 73 | return -EINVAL; 74 | 75 | greh = (struct gre_base_hdr *)(skb->data + nhs); 76 | if (unlikely(greh->flags & (GRE_VERSION | GRE_ROUTING))) 77 | return -EINVAL; 78 | 79 | tpi->flags = gre_flags_to_tnl_flags(greh->flags); 80 | hdr_len = gre_calc_hlen(tpi->flags); 81 | 82 | if (!pskb_may_pull(skb, nhs + hdr_len)) 83 | return -EINVAL; 84 | 85 | greh = (struct gre_base_hdr *)(skb->data + nhs); 86 | tpi->proto = greh->protocol; 87 | 88 | options = (__be32 *)(greh + 1); 89 | if (greh->flags & GRE_CSUM) { 90 | if (!skb_checksum_simple_validate(skb)) { 91 | skb_checksum_try_convert(skb, IPPROTO_GRE, 0, 92 | null_compute_pseudo); 93 | } else if (csum_err) { 94 | *csum_err = true; 95 | return -EINVAL; 96 | } 97 | 98 | options++; 99 | } 100 | 101 | if (greh->flags & GRE_KEY) { 102 | tpi->key = *options; 103 | options++; 104 | } else { 105 | tpi->key = 0; 106 | } 107 | if (unlikely(greh->flags & GRE_SEQ)) { 108 | tpi->seq = *options; 109 | options++; 110 | } else { 111 | tpi->seq = 0; 112 | } 113 | /* WCCP version 1 and 2 protocol decoding. 114 | * - Change protocol to IPv4/IPv6 115 | * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header 116 | */ 117 | if (greh->flags == 0 && tpi->proto == htons(ETH_P_WCCP)) { 118 | tpi->proto = proto; 119 | if ((*(u8 *)options & 0xF0) != 0x40) 120 | hdr_len += 4; 121 | } 122 | tpi->hdr_len = hdr_len; 123 | 124 | /* ERSPAN ver 1 and 2 protocol sets GRE key field 125 | * to 0 and sets the configured key in the 126 | * inner erspan header field 127 | */ 128 | if (greh->protocol == htons(ETH_P_ERSPAN) || 129 | greh->protocol == htons(ETH_P_ERSPAN2)) { 130 | struct erspan_base_hdr *ershdr; 131 | 132 | if (!pskb_may_pull(skb, nhs + hdr_len + sizeof(*ershdr))) 133 | return -EINVAL; 134 | 135 | ershdr = (struct erspan_base_hdr *)(skb->data + nhs + hdr_len); 136 | tpi->key = cpu_to_be32(get_session_id(ershdr)); 137 | } 138 | 139 | return hdr_len; 140 | } 141 | EXPORT_SYMBOL(gre_parse_header); 142 | 143 | static int gre_rcv(struct sk_buff *skb) 144 | { 145 | const struct gre_protocol *proto; 146 | u8 ver; 147 | int ret; 148 | 149 | if (!pskb_may_pull(skb, 12)) 150 | goto drop; 151 | 152 | ver = skb->data[1]&0x7f; 153 | if (ver >= GREPROTO_MAX) 154 | goto drop; 155 | 156 | rcu_read_lock(); 157 | proto = rcu_dereference(gre_proto[ver]); 158 | if (!proto || !proto->handler) 159 | goto drop_unlock; 160 | ret = proto->handler(skb); 161 | rcu_read_unlock(); 162 | return ret; 163 | 164 | drop_unlock: 165 | rcu_read_unlock(); 166 | drop: 167 | kfree_skb(skb); 168 | return NET_RX_DROP; 169 | } 170 | 171 | static void gre_err(struct sk_buff *skb, u32 info) 172 | { 173 | const struct gre_protocol *proto; 174 | const struct iphdr *iph = (const struct iphdr *)skb->data; 175 | u8 ver = skb->data[(iph->ihl<<2) + 1]&0x7f; 176 | 177 | if (ver >= GREPROTO_MAX) 178 | return; 179 | 180 | rcu_read_lock(); 181 | proto = rcu_dereference(gre_proto[ver]); 182 | if (proto && proto->err_handler) 183 | proto->err_handler(skb, info); 184 | rcu_read_unlock(); 185 | } 186 | 187 | static const struct net_protocol net_gre_protocol = { 188 | .handler = gre_rcv, 189 | .err_handler = gre_err, 190 | .netns_ok = 1, 191 | }; 192 | 193 | static int __init gre_init(void) 194 | { 195 | pr_info("GRE over IPv4 demultiplexor driver\n"); 196 | 197 | if (inet_add_protocol(&net_gre_protocol, IPPROTO_GRE) < 0) { 198 | pr_err("can't add protocol\n"); 199 | return -EAGAIN; 200 | } 201 | return 0; 202 | } 203 | 204 | static void __exit gre_exit(void) 205 | { 206 | inet_del_protocol(&net_gre_protocol, IPPROTO_GRE); 207 | } 208 | 209 | module_init(gre_init); 210 | module_exit(gre_exit); 211 | 212 | MODULE_DESCRIPTION("GRE over IPv4 demultiplexer driver"); 213 | MODULE_AUTHOR("D. Kozlov (xeb@mail.ru)"); 214 | MODULE_LICENSE("GPL"); 215 | -------------------------------------------------------------------------------- /out-of-tree-4.9.x/Makefile: -------------------------------------------------------------------------------- 1 | ifneq ($(KERNELRELEASE),) 2 | # ugly and dirty hack to avoid patching system's kernel headers 3 | ccflags-y += "-DGREPROTO_NONSTD_EOIP=0x80" 4 | ccflags-y += "-DGREPROTO_NONSTD_MAX=0x81" 5 | ccflags-y += "-DGREPROTO_NONSTD_BASE=0x80" 6 | obj-m := eoip.o 7 | obj-m += gre.o 8 | else 9 | KDIR ?= /lib/modules/`uname -r`/build 10 | default: eoip.c gre.c gre.h 11 | @$(MAKE) -C $(KDIR) M=$$PWD 12 | eoip.c: ../kernel-patch/kernel-4.9.0-eoip.patch 13 | @patch -p3 < $< 14 | gre.c gre.h: ../kernel-patch/kernel-4.9.0-eoip-gre-demux.patch 15 | @if [ -f /lib/modules/`uname -r`/build/net/ipv4/gre.c ]; then echo found running kernel version of gre.c; cp /lib/modules/`uname -r`/build/net/ipv4/gre_demux.c gre_demux.c; else echo using 4.9.0 version of gre_demux.c; cp gre_demux-4.9.0.c gre_demux.c; fi 16 | @if [ -f /lib/modules/`uname -r`/build/include/net/gre.h ]; then echo found running kernel version of gre.h; cp /lib/modules/`uname -r`/build/include/net/gre.h gre.h; else echo using 4.9.0 version of gre.h; cp gre-4.9.0.h gre.h; fi 17 | @patch -p3 < $< 18 | @cp gre_demux.c gre.c 19 | clean: 20 | @rm -f gre_demux.c gre.c gre.h eoip.c *.orig *.rej 21 | @$(MAKE) -C $(KDIR) M=$$PWD clean 22 | install modules_install: 23 | @$(MAKE) -C $(KDIR) M=$$PWD modules_install 24 | endif 25 | -------------------------------------------------------------------------------- /out-of-tree-4.9.x/gre-4.9.0.h: -------------------------------------------------------------------------------- 1 | #ifndef __LINUX_GRE_H 2 | #define __LINUX_GRE_H 3 | 4 | #include 5 | #include 6 | 7 | struct gre_base_hdr { 8 | __be16 flags; 9 | __be16 protocol; 10 | } __packed; 11 | 12 | struct gre_full_hdr { 13 | struct gre_base_hdr fixed_header; 14 | __be16 csum; 15 | __be16 reserved1; 16 | __be32 key; 17 | __be32 seq; 18 | } __packed; 19 | #define GRE_HEADER_SECTION 4 20 | 21 | #define GREPROTO_CISCO 0 22 | #define GREPROTO_PPTP 1 23 | #define GREPROTO_MAX 2 24 | #define GRE_IP_PROTO_MAX 2 25 | 26 | struct gre_protocol { 27 | int (*handler)(struct sk_buff *skb); 28 | void (*err_handler)(struct sk_buff *skb, u32 info); 29 | }; 30 | 31 | int gre_add_protocol(const struct gre_protocol *proto, u8 version); 32 | int gre_del_protocol(const struct gre_protocol *proto, u8 version); 33 | 34 | struct net_device *gretap_fb_dev_create(struct net *net, const char *name, 35 | u8 name_assign_type); 36 | int gre_parse_header(struct sk_buff *skb, struct tnl_ptk_info *tpi, 37 | bool *csum_err, __be16 proto, int nhs); 38 | 39 | static inline int gre_calc_hlen(__be16 o_flags) 40 | { 41 | int addend = 4; 42 | 43 | if (o_flags & TUNNEL_CSUM) 44 | addend += 4; 45 | if (o_flags & TUNNEL_KEY) 46 | addend += 4; 47 | if (o_flags & TUNNEL_SEQ) 48 | addend += 4; 49 | return addend; 50 | } 51 | 52 | static inline __be16 gre_flags_to_tnl_flags(__be16 flags) 53 | { 54 | __be16 tflags = 0; 55 | 56 | if (flags & GRE_CSUM) 57 | tflags |= TUNNEL_CSUM; 58 | if (flags & GRE_ROUTING) 59 | tflags |= TUNNEL_ROUTING; 60 | if (flags & GRE_KEY) 61 | tflags |= TUNNEL_KEY; 62 | if (flags & GRE_SEQ) 63 | tflags |= TUNNEL_SEQ; 64 | if (flags & GRE_STRICT) 65 | tflags |= TUNNEL_STRICT; 66 | if (flags & GRE_REC) 67 | tflags |= TUNNEL_REC; 68 | if (flags & GRE_VERSION) 69 | tflags |= TUNNEL_VERSION; 70 | 71 | return tflags; 72 | } 73 | 74 | static inline __be16 gre_tnl_flags_to_gre_flags(__be16 tflags) 75 | { 76 | __be16 flags = 0; 77 | 78 | if (tflags & TUNNEL_CSUM) 79 | flags |= GRE_CSUM; 80 | if (tflags & TUNNEL_ROUTING) 81 | flags |= GRE_ROUTING; 82 | if (tflags & TUNNEL_KEY) 83 | flags |= GRE_KEY; 84 | if (tflags & TUNNEL_SEQ) 85 | flags |= GRE_SEQ; 86 | if (tflags & TUNNEL_STRICT) 87 | flags |= GRE_STRICT; 88 | if (tflags & TUNNEL_REC) 89 | flags |= GRE_REC; 90 | if (tflags & TUNNEL_VERSION) 91 | flags |= GRE_VERSION; 92 | 93 | return flags; 94 | } 95 | 96 | static inline __sum16 gre_checksum(struct sk_buff *skb) 97 | { 98 | __wsum csum; 99 | 100 | if (skb->ip_summed == CHECKSUM_PARTIAL) 101 | csum = lco_csum(skb); 102 | else 103 | csum = skb_checksum(skb, 0, skb->len, 0); 104 | return csum_fold(csum); 105 | } 106 | 107 | static inline void gre_build_header(struct sk_buff *skb, int hdr_len, 108 | __be16 flags, __be16 proto, 109 | __be32 key, __be32 seq) 110 | { 111 | struct gre_base_hdr *greh; 112 | 113 | skb_push(skb, hdr_len); 114 | 115 | skb_set_inner_protocol(skb, proto); 116 | skb_reset_transport_header(skb); 117 | greh = (struct gre_base_hdr *)skb->data; 118 | greh->flags = gre_tnl_flags_to_gre_flags(flags); 119 | greh->protocol = proto; 120 | 121 | if (flags & (TUNNEL_KEY | TUNNEL_CSUM | TUNNEL_SEQ)) { 122 | __be32 *ptr = (__be32 *)(((u8 *)greh) + hdr_len - 4); 123 | 124 | if (flags & TUNNEL_SEQ) { 125 | *ptr = seq; 126 | ptr--; 127 | } 128 | if (flags & TUNNEL_KEY) { 129 | *ptr = key; 130 | ptr--; 131 | } 132 | if (flags & TUNNEL_CSUM && 133 | !(skb_shinfo(skb)->gso_type & 134 | (SKB_GSO_GRE | SKB_GSO_GRE_CSUM))) { 135 | *ptr = 0; 136 | *(__sum16 *)ptr = gre_checksum(skb); 137 | } 138 | } 139 | } 140 | 141 | #endif 142 | -------------------------------------------------------------------------------- /out-of-tree-4.9.x/gre_demux-4.9.0.c: -------------------------------------------------------------------------------- 1 | /* 2 | * GRE over IPv4 demultiplexer driver 3 | * 4 | * Authors: Dmitry Kozlov (xeb@mail.ru) 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 9 | * 2 of the License, or (at your option) any later version. 10 | * 11 | */ 12 | 13 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | static const struct gre_protocol __rcu *gre_proto[GREPROTO_MAX] __read_mostly; 34 | 35 | int gre_add_protocol(const struct gre_protocol *proto, u8 version) 36 | { 37 | if (version >= GREPROTO_MAX) 38 | return -EINVAL; 39 | 40 | return (cmpxchg((const struct gre_protocol **)&gre_proto[version], NULL, proto) == NULL) ? 41 | 0 : -EBUSY; 42 | } 43 | EXPORT_SYMBOL_GPL(gre_add_protocol); 44 | 45 | int gre_del_protocol(const struct gre_protocol *proto, u8 version) 46 | { 47 | int ret; 48 | 49 | if (version >= GREPROTO_MAX) 50 | return -EINVAL; 51 | 52 | ret = (cmpxchg((const struct gre_protocol **)&gre_proto[version], proto, NULL) == proto) ? 53 | 0 : -EBUSY; 54 | 55 | if (ret) 56 | return ret; 57 | 58 | synchronize_rcu(); 59 | return 0; 60 | } 61 | EXPORT_SYMBOL_GPL(gre_del_protocol); 62 | 63 | /* Fills in tpi and returns header length to be pulled. 64 | * Note that caller must use pskb_may_pull() before pulling GRE header. 65 | */ 66 | int gre_parse_header(struct sk_buff *skb, struct tnl_ptk_info *tpi, 67 | bool *csum_err, __be16 proto, int nhs) 68 | { 69 | const struct gre_base_hdr *greh; 70 | __be32 *options; 71 | int hdr_len; 72 | 73 | if (unlikely(!pskb_may_pull(skb, nhs + sizeof(struct gre_base_hdr)))) 74 | return -EINVAL; 75 | 76 | greh = (struct gre_base_hdr *)(skb->data + nhs); 77 | if (unlikely(greh->flags & (GRE_VERSION | GRE_ROUTING))) 78 | return -EINVAL; 79 | 80 | tpi->flags = gre_flags_to_tnl_flags(greh->flags); 81 | hdr_len = gre_calc_hlen(tpi->flags); 82 | 83 | if (!pskb_may_pull(skb, nhs + hdr_len)) 84 | return -EINVAL; 85 | 86 | greh = (struct gre_base_hdr *)(skb->data + nhs); 87 | tpi->proto = greh->protocol; 88 | 89 | options = (__be32 *)(greh + 1); 90 | if (greh->flags & GRE_CSUM) { 91 | if (!skb_checksum_simple_validate(skb)) { 92 | skb_checksum_try_convert(skb, IPPROTO_GRE, 0, 93 | null_compute_pseudo); 94 | } else if (csum_err) { 95 | *csum_err = true; 96 | return -EINVAL; 97 | } 98 | 99 | options++; 100 | } 101 | 102 | if (greh->flags & GRE_KEY) { 103 | tpi->key = *options; 104 | options++; 105 | } else { 106 | tpi->key = 0; 107 | } 108 | if (unlikely(greh->flags & GRE_SEQ)) { 109 | tpi->seq = *options; 110 | options++; 111 | } else { 112 | tpi->seq = 0; 113 | } 114 | /* WCCP version 1 and 2 protocol decoding. 115 | * - Change protocol to IPv4/IPv6 116 | * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header 117 | */ 118 | if (greh->flags == 0 && tpi->proto == htons(ETH_P_WCCP)) { 119 | u8 _val, *val; 120 | 121 | val = skb_header_pointer(skb, nhs + hdr_len, 122 | sizeof(_val), &_val); 123 | if (!val) 124 | return -EINVAL; 125 | tpi->proto = proto; 126 | if ((*val & 0xF0) != 0x40) 127 | hdr_len += 4; 128 | } 129 | tpi->hdr_len = hdr_len; 130 | return hdr_len; 131 | } 132 | EXPORT_SYMBOL(gre_parse_header); 133 | 134 | static int gre_rcv(struct sk_buff *skb) 135 | { 136 | const struct gre_protocol *proto; 137 | u8 ver; 138 | int ret; 139 | 140 | if (!pskb_may_pull(skb, 12)) 141 | goto drop; 142 | 143 | ver = skb->data[1]&0x7f; 144 | if (ver >= GREPROTO_MAX) 145 | goto drop; 146 | 147 | rcu_read_lock(); 148 | proto = rcu_dereference(gre_proto[ver]); 149 | if (!proto || !proto->handler) 150 | goto drop_unlock; 151 | ret = proto->handler(skb); 152 | rcu_read_unlock(); 153 | return ret; 154 | 155 | drop_unlock: 156 | rcu_read_unlock(); 157 | drop: 158 | kfree_skb(skb); 159 | return NET_RX_DROP; 160 | } 161 | 162 | static void gre_err(struct sk_buff *skb, u32 info) 163 | { 164 | const struct gre_protocol *proto; 165 | const struct iphdr *iph = (const struct iphdr *)skb->data; 166 | u8 ver = skb->data[(iph->ihl<<2) + 1]&0x7f; 167 | 168 | if (ver >= GREPROTO_MAX) 169 | return; 170 | 171 | rcu_read_lock(); 172 | proto = rcu_dereference(gre_proto[ver]); 173 | if (proto && proto->err_handler) 174 | proto->err_handler(skb, info); 175 | rcu_read_unlock(); 176 | } 177 | 178 | static const struct net_protocol net_gre_protocol = { 179 | .handler = gre_rcv, 180 | .err_handler = gre_err, 181 | .netns_ok = 1, 182 | }; 183 | 184 | static int __init gre_init(void) 185 | { 186 | pr_info("GRE over IPv4 demultiplexor driver\n"); 187 | 188 | if (inet_add_protocol(&net_gre_protocol, IPPROTO_GRE) < 0) { 189 | pr_err("can't add protocol\n"); 190 | return -EAGAIN; 191 | } 192 | return 0; 193 | } 194 | 195 | static void __exit gre_exit(void) 196 | { 197 | inet_del_protocol(&net_gre_protocol, IPPROTO_GRE); 198 | } 199 | 200 | module_init(gre_init); 201 | module_exit(gre_exit); 202 | 203 | MODULE_DESCRIPTION("GRE over IPv4 demultiplexer driver"); 204 | MODULE_AUTHOR("D. Kozlov (xeb@mail.ru)"); 205 | MODULE_LICENSE("GPL"); 206 | -------------------------------------------------------------------------------- /out-of-tree-5.10.x: -------------------------------------------------------------------------------- 1 | out-of-tree-5.6.x -------------------------------------------------------------------------------- /out-of-tree-5.14.x/Makefile: -------------------------------------------------------------------------------- 1 | ifneq ($(KERNELRELEASE),) 2 | # ugly and dirty hack to avoid patching system's kernel headers 3 | ccflags-y += "-DGREPROTO_NONSTD_EOIP=0x80" 4 | ccflags-y += "-DGREPROTO_NONSTD_MAX=0x81" 5 | ccflags-y += "-DGREPROTO_NONSTD_BASE=0x80" 6 | obj-m := eoip.o 7 | obj-m += gre.o 8 | else 9 | KDIR ?= /lib/modules/`uname -r`/build 10 | default: eoip.c gre.c gre.h 11 | @$(MAKE) -C $(KDIR) M=$$PWD 12 | eoip.c: ../kernel-patch/kernel-5.6.0-eoip.patch 13 | @patch -p3 < $< 14 | gre.c gre.h: ../kernel-patch/kernel-5.6.0-eoip-gre-demux.patch 15 | @if [ -f /lib/modules/`uname -r`/build/net/ipv4/gre.c ]; then echo found running kernel version of gre.c; cp /lib/modules/`uname -r`/build/net/ipv4/gre_demux.c gre_demux.c; else echo using 5.14.0 version of gre_demux.c; cp gre_demux-5.14.0.c gre_demux.c; fi 16 | @if [ -f /lib/modules/`uname -r`/build/include/net/gre.h ]; then echo found running kernel version of gre.h; cp /lib/modules/`uname -r`/build/include/net/gre.h gre.h; else echo using 5.14.0 version of gre.h; cp gre-5.14.0.h gre.h; fi 17 | @patch -p3 < $< 18 | @cp gre_demux.c gre.c 19 | clean: 20 | @rm -f gre_demux.c gre.c gre.h eoip.c *.orig *.rej 21 | @$(MAKE) -C $(KDIR) M=$$PWD clean 22 | install modules_install: 23 | @$(MAKE) -C $(KDIR) M=$$PWD modules_install 24 | endif 25 | -------------------------------------------------------------------------------- /out-of-tree-5.14.x/gre-5.14.0.h: -------------------------------------------------------------------------------- 1 | ../out-of-tree-5.6.x/gre-5.6.0.h -------------------------------------------------------------------------------- /out-of-tree-5.14.x/gre_demux-5.14.0.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * GRE over IPv4 demultiplexer driver 4 | * 5 | * Authors: Dmitry Kozlov (xeb@mail.ru) 6 | */ 7 | 8 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | static const struct gre_protocol __rcu *gre_proto[GREPROTO_MAX] __read_mostly; 30 | 31 | int gre_add_protocol(const struct gre_protocol *proto, u8 version) 32 | { 33 | if (version >= GREPROTO_MAX) 34 | return -EINVAL; 35 | 36 | return (cmpxchg((const struct gre_protocol **)&gre_proto[version], NULL, proto) == NULL) ? 37 | 0 : -EBUSY; 38 | } 39 | EXPORT_SYMBOL_GPL(gre_add_protocol); 40 | 41 | int gre_del_protocol(const struct gre_protocol *proto, u8 version) 42 | { 43 | int ret; 44 | 45 | if (version >= GREPROTO_MAX) 46 | return -EINVAL; 47 | 48 | ret = (cmpxchg((const struct gre_protocol **)&gre_proto[version], proto, NULL) == proto) ? 49 | 0 : -EBUSY; 50 | 51 | if (ret) 52 | return ret; 53 | 54 | synchronize_rcu(); 55 | return 0; 56 | } 57 | EXPORT_SYMBOL_GPL(gre_del_protocol); 58 | 59 | /* Fills in tpi and returns header length to be pulled. 60 | * Note that caller must use pskb_may_pull() before pulling GRE header. 61 | */ 62 | int gre_parse_header(struct sk_buff *skb, struct tnl_ptk_info *tpi, 63 | bool *csum_err, __be16 proto, int nhs) 64 | { 65 | const struct gre_base_hdr *greh; 66 | __be32 *options; 67 | int hdr_len; 68 | 69 | if (unlikely(!pskb_may_pull(skb, nhs + sizeof(struct gre_base_hdr)))) 70 | return -EINVAL; 71 | 72 | greh = (struct gre_base_hdr *)(skb->data + nhs); 73 | if (unlikely(greh->flags & (GRE_VERSION | GRE_ROUTING))) 74 | return -EINVAL; 75 | 76 | tpi->flags = gre_flags_to_tnl_flags(greh->flags); 77 | hdr_len = gre_calc_hlen(tpi->flags); 78 | 79 | if (!pskb_may_pull(skb, nhs + hdr_len)) 80 | return -EINVAL; 81 | 82 | greh = (struct gre_base_hdr *)(skb->data + nhs); 83 | tpi->proto = greh->protocol; 84 | 85 | options = (__be32 *)(greh + 1); 86 | if (greh->flags & GRE_CSUM) { 87 | if (!skb_checksum_simple_validate(skb)) { 88 | skb_checksum_try_convert(skb, IPPROTO_GRE, 89 | null_compute_pseudo); 90 | } else if (csum_err) { 91 | *csum_err = true; 92 | return -EINVAL; 93 | } 94 | 95 | options++; 96 | } 97 | 98 | if (greh->flags & GRE_KEY) { 99 | tpi->key = *options; 100 | options++; 101 | } else { 102 | tpi->key = 0; 103 | } 104 | if (unlikely(greh->flags & GRE_SEQ)) { 105 | tpi->seq = *options; 106 | options++; 107 | } else { 108 | tpi->seq = 0; 109 | } 110 | /* WCCP version 1 and 2 protocol decoding. 111 | * - Change protocol to IPv4/IPv6 112 | * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header 113 | */ 114 | if (greh->flags == 0 && tpi->proto == htons(ETH_P_WCCP)) { 115 | u8 _val, *val; 116 | 117 | val = skb_header_pointer(skb, nhs + hdr_len, 118 | sizeof(_val), &_val); 119 | if (!val) 120 | return -EINVAL; 121 | tpi->proto = proto; 122 | if ((*val & 0xF0) != 0x40) 123 | hdr_len += 4; 124 | } 125 | tpi->hdr_len = hdr_len; 126 | 127 | /* ERSPAN ver 1 and 2 protocol sets GRE key field 128 | * to 0 and sets the configured key in the 129 | * inner erspan header field 130 | */ 131 | if (greh->protocol == htons(ETH_P_ERSPAN) || 132 | greh->protocol == htons(ETH_P_ERSPAN2)) { 133 | struct erspan_base_hdr *ershdr; 134 | 135 | if (!pskb_may_pull(skb, nhs + hdr_len + sizeof(*ershdr))) 136 | return -EINVAL; 137 | 138 | ershdr = (struct erspan_base_hdr *)(skb->data + nhs + hdr_len); 139 | tpi->key = cpu_to_be32(get_session_id(ershdr)); 140 | } 141 | 142 | return hdr_len; 143 | } 144 | EXPORT_SYMBOL(gre_parse_header); 145 | 146 | static int gre_rcv(struct sk_buff *skb) 147 | { 148 | const struct gre_protocol *proto; 149 | u8 ver; 150 | int ret; 151 | 152 | if (!pskb_may_pull(skb, 12)) 153 | goto drop; 154 | 155 | ver = skb->data[1]&0x7f; 156 | if (ver >= GREPROTO_MAX) 157 | goto drop; 158 | 159 | rcu_read_lock(); 160 | proto = rcu_dereference(gre_proto[ver]); 161 | if (!proto || !proto->handler) 162 | goto drop_unlock; 163 | ret = proto->handler(skb); 164 | rcu_read_unlock(); 165 | return ret; 166 | 167 | drop_unlock: 168 | rcu_read_unlock(); 169 | drop: 170 | kfree_skb(skb); 171 | return NET_RX_DROP; 172 | } 173 | 174 | static int gre_err(struct sk_buff *skb, u32 info) 175 | { 176 | const struct gre_protocol *proto; 177 | const struct iphdr *iph = (const struct iphdr *)skb->data; 178 | u8 ver = skb->data[(iph->ihl<<2) + 1]&0x7f; 179 | int err = 0; 180 | 181 | if (ver >= GREPROTO_MAX) 182 | return -EINVAL; 183 | 184 | rcu_read_lock(); 185 | proto = rcu_dereference(gre_proto[ver]); 186 | if (proto && proto->err_handler) 187 | proto->err_handler(skb, info); 188 | else 189 | err = -EPROTONOSUPPORT; 190 | rcu_read_unlock(); 191 | 192 | return err; 193 | } 194 | 195 | static const struct net_protocol net_gre_protocol = { 196 | .handler = gre_rcv, 197 | .err_handler = gre_err, 198 | }; 199 | 200 | static int __init gre_init(void) 201 | { 202 | pr_info("GRE over IPv4 demultiplexor driver\n"); 203 | 204 | if (inet_add_protocol(&net_gre_protocol, IPPROTO_GRE) < 0) { 205 | pr_err("can't add protocol\n"); 206 | return -EAGAIN; 207 | } 208 | return 0; 209 | } 210 | 211 | static void __exit gre_exit(void) 212 | { 213 | inet_del_protocol(&net_gre_protocol, IPPROTO_GRE); 214 | } 215 | 216 | module_init(gre_init); 217 | module_exit(gre_exit); 218 | 219 | MODULE_DESCRIPTION("GRE over IPv4 demultiplexer driver"); 220 | MODULE_AUTHOR("D. Kozlov (xeb@mail.ru)"); 221 | MODULE_LICENSE("GPL"); 222 | -------------------------------------------------------------------------------- /out-of-tree-5.17.x/Makefile: -------------------------------------------------------------------------------- 1 | ifneq ($(KERNELRELEASE),) 2 | # ugly and dirty hack to avoid patching system's kernel headers 3 | ccflags-y += "-DGREPROTO_NONSTD_EOIP=0x80" 4 | ccflags-y += "-DGREPROTO_NONSTD_MAX=0x81" 5 | ccflags-y += "-DGREPROTO_NONSTD_BASE=0x80" 6 | obj-m := eoip.o 7 | obj-m += gre.o 8 | else 9 | KDIR ?= /lib/modules/`uname -r`/build 10 | default: eoip.c gre.c gre.h 11 | @$(MAKE) -C $(KDIR) M=$$PWD 12 | eoip.c: ../kernel-patch/kernel-5.17.0-eoip.patch 13 | @patch -p3 < $< 14 | gre.c gre.h: ../kernel-patch/kernel-5.17.0-eoip-gre-demux.patch 15 | @if [ -f /lib/modules/`uname -r`/build/net/ipv4/gre.c ]; then echo found running kernel version of gre.c; cp /lib/modules/`uname -r`/build/net/ipv4/gre_demux.c gre_demux.c; else echo using 5.17.0 version of gre_demux.c; cp gre_demux-5.17.0.c gre_demux.c; fi 16 | @if [ -f /lib/modules/`uname -r`/build/include/net/gre.h ]; then echo found running kernel version of gre.h; cp /lib/modules/`uname -r`/build/include/net/gre.h gre.h; else echo using 5.17.0 version of gre.h; cp gre-5.17.0.h gre.h; fi 17 | @patch -p3 < $< 18 | @cp gre_demux.c gre.c 19 | clean: 20 | @rm -f gre_demux.c gre.c gre.h eoip.c *.orig *.rej 21 | @$(MAKE) -C $(KDIR) M=$$PWD clean 22 | install modules_install: 23 | @$(MAKE) -C $(KDIR) M=$$PWD modules_install 24 | endif 25 | -------------------------------------------------------------------------------- /out-of-tree-5.17.x/gre-5.17.0.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | #ifndef __LINUX_GRE_H 3 | #define __LINUX_GRE_H 4 | 5 | #include 6 | #include 7 | 8 | struct gre_base_hdr { 9 | __be16 flags; 10 | __be16 protocol; 11 | } __packed; 12 | 13 | struct gre_full_hdr { 14 | struct gre_base_hdr fixed_header; 15 | __be16 csum; 16 | __be16 reserved1; 17 | __be32 key; 18 | __be32 seq; 19 | } __packed; 20 | #define GRE_HEADER_SECTION 4 21 | 22 | #define GREPROTO_CISCO 0 23 | #define GREPROTO_PPTP 1 24 | #define GREPROTO_MAX 2 25 | #define GRE_IP_PROTO_MAX 2 26 | 27 | struct gre_protocol { 28 | int (*handler)(struct sk_buff *skb); 29 | void (*err_handler)(struct sk_buff *skb, u32 info); 30 | }; 31 | 32 | int gre_add_protocol(const struct gre_protocol *proto, u8 version); 33 | int gre_del_protocol(const struct gre_protocol *proto, u8 version); 34 | 35 | struct net_device *gretap_fb_dev_create(struct net *net, const char *name, 36 | u8 name_assign_type); 37 | int gre_parse_header(struct sk_buff *skb, struct tnl_ptk_info *tpi, 38 | bool *csum_err, __be16 proto, int nhs); 39 | 40 | static inline bool netif_is_gretap(const struct net_device *dev) 41 | { 42 | return dev->rtnl_link_ops && 43 | !strcmp(dev->rtnl_link_ops->kind, "gretap"); 44 | } 45 | 46 | static inline bool netif_is_ip6gretap(const struct net_device *dev) 47 | { 48 | return dev->rtnl_link_ops && 49 | !strcmp(dev->rtnl_link_ops->kind, "ip6gretap"); 50 | } 51 | 52 | static inline int gre_calc_hlen(__be16 o_flags) 53 | { 54 | int addend = 4; 55 | 56 | if (o_flags & TUNNEL_CSUM) 57 | addend += 4; 58 | if (o_flags & TUNNEL_KEY) 59 | addend += 4; 60 | if (o_flags & TUNNEL_SEQ) 61 | addend += 4; 62 | return addend; 63 | } 64 | 65 | static inline __be16 gre_flags_to_tnl_flags(__be16 flags) 66 | { 67 | __be16 tflags = 0; 68 | 69 | if (flags & GRE_CSUM) 70 | tflags |= TUNNEL_CSUM; 71 | if (flags & GRE_ROUTING) 72 | tflags |= TUNNEL_ROUTING; 73 | if (flags & GRE_KEY) 74 | tflags |= TUNNEL_KEY; 75 | if (flags & GRE_SEQ) 76 | tflags |= TUNNEL_SEQ; 77 | if (flags & GRE_STRICT) 78 | tflags |= TUNNEL_STRICT; 79 | if (flags & GRE_REC) 80 | tflags |= TUNNEL_REC; 81 | if (flags & GRE_VERSION) 82 | tflags |= TUNNEL_VERSION; 83 | 84 | return tflags; 85 | } 86 | 87 | static inline __be16 gre_tnl_flags_to_gre_flags(__be16 tflags) 88 | { 89 | __be16 flags = 0; 90 | 91 | if (tflags & TUNNEL_CSUM) 92 | flags |= GRE_CSUM; 93 | if (tflags & TUNNEL_ROUTING) 94 | flags |= GRE_ROUTING; 95 | if (tflags & TUNNEL_KEY) 96 | flags |= GRE_KEY; 97 | if (tflags & TUNNEL_SEQ) 98 | flags |= GRE_SEQ; 99 | if (tflags & TUNNEL_STRICT) 100 | flags |= GRE_STRICT; 101 | if (tflags & TUNNEL_REC) 102 | flags |= GRE_REC; 103 | if (tflags & TUNNEL_VERSION) 104 | flags |= GRE_VERSION; 105 | 106 | return flags; 107 | } 108 | 109 | static inline void gre_build_header(struct sk_buff *skb, int hdr_len, 110 | __be16 flags, __be16 proto, 111 | __be32 key, __be32 seq) 112 | { 113 | struct gre_base_hdr *greh; 114 | 115 | skb_push(skb, hdr_len); 116 | 117 | skb_set_inner_protocol(skb, proto); 118 | skb_reset_transport_header(skb); 119 | greh = (struct gre_base_hdr *)skb->data; 120 | greh->flags = gre_tnl_flags_to_gre_flags(flags); 121 | greh->protocol = proto; 122 | 123 | if (flags & (TUNNEL_KEY | TUNNEL_CSUM | TUNNEL_SEQ)) { 124 | __be32 *ptr = (__be32 *)(((u8 *)greh) + hdr_len - 4); 125 | 126 | if (flags & TUNNEL_SEQ) { 127 | *ptr = seq; 128 | ptr--; 129 | } 130 | if (flags & TUNNEL_KEY) { 131 | *ptr = key; 132 | ptr--; 133 | } 134 | if (flags & TUNNEL_CSUM && 135 | !(skb_shinfo(skb)->gso_type & 136 | (SKB_GSO_GRE | SKB_GSO_GRE_CSUM))) { 137 | *ptr = 0; 138 | if (skb->ip_summed == CHECKSUM_PARTIAL) { 139 | *(__sum16 *)ptr = csum_fold(lco_csum(skb)); 140 | } else { 141 | skb->ip_summed = CHECKSUM_PARTIAL; 142 | skb->csum_start = skb_transport_header(skb) - skb->head; 143 | skb->csum_offset = sizeof(*greh); 144 | } 145 | } 146 | } 147 | } 148 | 149 | #endif 150 | -------------------------------------------------------------------------------- /out-of-tree-5.17.x/gre_demux-5.17.0.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * GRE over IPv4 demultiplexer driver 4 | * 5 | * Authors: Dmitry Kozlov (xeb@mail.ru) 6 | */ 7 | 8 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | static const struct gre_protocol __rcu *gre_proto[GREPROTO_MAX] __read_mostly; 30 | 31 | int gre_add_protocol(const struct gre_protocol *proto, u8 version) 32 | { 33 | if (version >= GREPROTO_MAX) 34 | return -EINVAL; 35 | 36 | return (cmpxchg((const struct gre_protocol **)&gre_proto[version], NULL, proto) == NULL) ? 37 | 0 : -EBUSY; 38 | } 39 | EXPORT_SYMBOL_GPL(gre_add_protocol); 40 | 41 | int gre_del_protocol(const struct gre_protocol *proto, u8 version) 42 | { 43 | int ret; 44 | 45 | if (version >= GREPROTO_MAX) 46 | return -EINVAL; 47 | 48 | ret = (cmpxchg((const struct gre_protocol **)&gre_proto[version], proto, NULL) == proto) ? 49 | 0 : -EBUSY; 50 | 51 | if (ret) 52 | return ret; 53 | 54 | synchronize_rcu(); 55 | return 0; 56 | } 57 | EXPORT_SYMBOL_GPL(gre_del_protocol); 58 | 59 | /* Fills in tpi and returns header length to be pulled. 60 | * Note that caller must use pskb_may_pull() before pulling GRE header. 61 | */ 62 | int gre_parse_header(struct sk_buff *skb, struct tnl_ptk_info *tpi, 63 | bool *csum_err, __be16 proto, int nhs) 64 | { 65 | const struct gre_base_hdr *greh; 66 | __be32 *options; 67 | int hdr_len; 68 | 69 | if (unlikely(!pskb_may_pull(skb, nhs + sizeof(struct gre_base_hdr)))) 70 | return -EINVAL; 71 | 72 | greh = (struct gre_base_hdr *)(skb->data + nhs); 73 | if (unlikely(greh->flags & (GRE_VERSION | GRE_ROUTING))) 74 | return -EINVAL; 75 | 76 | tpi->flags = gre_flags_to_tnl_flags(greh->flags); 77 | hdr_len = gre_calc_hlen(tpi->flags); 78 | 79 | if (!pskb_may_pull(skb, nhs + hdr_len)) 80 | return -EINVAL; 81 | 82 | greh = (struct gre_base_hdr *)(skb->data + nhs); 83 | tpi->proto = greh->protocol; 84 | 85 | options = (__be32 *)(greh + 1); 86 | if (greh->flags & GRE_CSUM) { 87 | if (!skb_checksum_simple_validate(skb)) { 88 | skb_checksum_try_convert(skb, IPPROTO_GRE, 89 | null_compute_pseudo); 90 | } else if (csum_err) { 91 | *csum_err = true; 92 | return -EINVAL; 93 | } 94 | 95 | options++; 96 | } 97 | 98 | if (greh->flags & GRE_KEY) { 99 | tpi->key = *options; 100 | options++; 101 | } else { 102 | tpi->key = 0; 103 | } 104 | if (unlikely(greh->flags & GRE_SEQ)) { 105 | tpi->seq = *options; 106 | options++; 107 | } else { 108 | tpi->seq = 0; 109 | } 110 | /* WCCP version 1 and 2 protocol decoding. 111 | * - Change protocol to IPv4/IPv6 112 | * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header 113 | */ 114 | if (greh->flags == 0 && tpi->proto == htons(ETH_P_WCCP)) { 115 | u8 _val, *val; 116 | 117 | val = skb_header_pointer(skb, nhs + hdr_len, 118 | sizeof(_val), &_val); 119 | if (!val) 120 | return -EINVAL; 121 | tpi->proto = proto; 122 | if ((*val & 0xF0) != 0x40) 123 | hdr_len += 4; 124 | } 125 | tpi->hdr_len = hdr_len; 126 | 127 | /* ERSPAN ver 1 and 2 protocol sets GRE key field 128 | * to 0 and sets the configured key in the 129 | * inner erspan header field 130 | */ 131 | if ((greh->protocol == htons(ETH_P_ERSPAN) && hdr_len != 4) || 132 | greh->protocol == htons(ETH_P_ERSPAN2)) { 133 | struct erspan_base_hdr *ershdr; 134 | 135 | if (!pskb_may_pull(skb, nhs + hdr_len + sizeof(*ershdr))) 136 | return -EINVAL; 137 | 138 | ershdr = (struct erspan_base_hdr *)(skb->data + nhs + hdr_len); 139 | tpi->key = cpu_to_be32(get_session_id(ershdr)); 140 | } 141 | 142 | return hdr_len; 143 | } 144 | EXPORT_SYMBOL(gre_parse_header); 145 | 146 | static int gre_rcv(struct sk_buff *skb) 147 | { 148 | const struct gre_protocol *proto; 149 | u8 ver; 150 | int ret; 151 | 152 | if (!pskb_may_pull(skb, 12)) 153 | goto drop; 154 | 155 | ver = skb->data[1]&0x7f; 156 | if (ver >= GREPROTO_MAX) 157 | goto drop; 158 | 159 | rcu_read_lock(); 160 | proto = rcu_dereference(gre_proto[ver]); 161 | if (!proto || !proto->handler) 162 | goto drop_unlock; 163 | ret = proto->handler(skb); 164 | rcu_read_unlock(); 165 | return ret; 166 | 167 | drop_unlock: 168 | rcu_read_unlock(); 169 | drop: 170 | kfree_skb(skb); 171 | return NET_RX_DROP; 172 | } 173 | 174 | static int gre_err(struct sk_buff *skb, u32 info) 175 | { 176 | const struct gre_protocol *proto; 177 | const struct iphdr *iph = (const struct iphdr *)skb->data; 178 | u8 ver = skb->data[(iph->ihl<<2) + 1]&0x7f; 179 | int err = 0; 180 | 181 | if (ver >= GREPROTO_MAX) 182 | return -EINVAL; 183 | 184 | rcu_read_lock(); 185 | proto = rcu_dereference(gre_proto[ver]); 186 | if (proto && proto->err_handler) 187 | proto->err_handler(skb, info); 188 | else 189 | err = -EPROTONOSUPPORT; 190 | rcu_read_unlock(); 191 | 192 | return err; 193 | } 194 | 195 | static const struct net_protocol net_gre_protocol = { 196 | .handler = gre_rcv, 197 | .err_handler = gre_err, 198 | }; 199 | 200 | static int __init gre_init(void) 201 | { 202 | pr_info("GRE over IPv4 demultiplexor driver\n"); 203 | 204 | if (inet_add_protocol(&net_gre_protocol, IPPROTO_GRE) < 0) { 205 | pr_err("can't add protocol\n"); 206 | return -EAGAIN; 207 | } 208 | return 0; 209 | } 210 | 211 | static void __exit gre_exit(void) 212 | { 213 | inet_del_protocol(&net_gre_protocol, IPPROTO_GRE); 214 | } 215 | 216 | module_init(gre_init); 217 | module_exit(gre_exit); 218 | 219 | MODULE_DESCRIPTION("GRE over IPv4 demultiplexer driver"); 220 | MODULE_AUTHOR("D. Kozlov (xeb@mail.ru)"); 221 | MODULE_LICENSE("GPL"); 222 | -------------------------------------------------------------------------------- /out-of-tree-5.19.x: -------------------------------------------------------------------------------- 1 | out-of-tree-5.17.x -------------------------------------------------------------------------------- /out-of-tree-5.4.x: -------------------------------------------------------------------------------- 1 | out-of-tree-5.6.x -------------------------------------------------------------------------------- /out-of-tree-5.6.x/Makefile: -------------------------------------------------------------------------------- 1 | ifneq ($(KERNELRELEASE),) 2 | # ugly and dirty hack to avoid patching system's kernel headers 3 | ccflags-y += "-DGREPROTO_NONSTD_EOIP=0x80" 4 | ccflags-y += "-DGREPROTO_NONSTD_MAX=0x81" 5 | ccflags-y += "-DGREPROTO_NONSTD_BASE=0x80" 6 | obj-m := eoip.o 7 | obj-m += gre.o 8 | else 9 | KDIR ?= /lib/modules/`uname -r`/build 10 | default: eoip.c gre.c gre.h 11 | @$(MAKE) -C $(KDIR) M=$$PWD 12 | eoip.c: ../kernel-patch/kernel-5.6.0-eoip.patch 13 | @patch -p3 < $< 14 | gre.c gre.h: ../kernel-patch/kernel-5.6.0-eoip-gre-demux.patch 15 | @if [ -f /lib/modules/`uname -r`/build/net/ipv4/gre.c ]; then echo found running kernel version of gre.c; cp /lib/modules/`uname -r`/build/net/ipv4/gre_demux.c gre_demux.c; else echo using 5.6.0 version of gre_demux.c; cp gre_demux-5.6.0.c gre_demux.c; fi 16 | @if [ -f /lib/modules/`uname -r`/build/include/net/gre.h ]; then echo found running kernel version of gre.h; cp /lib/modules/`uname -r`/build/include/net/gre.h gre.h; else echo using 5.6.0 version of gre.h; cp gre-5.6.0.h gre.h; fi 17 | @patch -p3 < $< 18 | @cp gre_demux.c gre.c 19 | clean: 20 | @rm -f gre_demux.c gre.c gre.h eoip.c *.orig *.rej 21 | @$(MAKE) -C $(KDIR) M=$$PWD clean 22 | install modules_install: 23 | @$(MAKE) -C $(KDIR) M=$$PWD modules_install 24 | endif 25 | -------------------------------------------------------------------------------- /out-of-tree-5.6.x/gre-5.6.0.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | #ifndef __LINUX_GRE_H 3 | #define __LINUX_GRE_H 4 | 5 | #include 6 | #include 7 | 8 | struct gre_base_hdr { 9 | __be16 flags; 10 | __be16 protocol; 11 | } __packed; 12 | 13 | struct gre_full_hdr { 14 | struct gre_base_hdr fixed_header; 15 | __be16 csum; 16 | __be16 reserved1; 17 | __be32 key; 18 | __be32 seq; 19 | } __packed; 20 | #define GRE_HEADER_SECTION 4 21 | 22 | #define GREPROTO_CISCO 0 23 | #define GREPROTO_PPTP 1 24 | #define GREPROTO_MAX 2 25 | #define GRE_IP_PROTO_MAX 2 26 | 27 | struct gre_protocol { 28 | int (*handler)(struct sk_buff *skb); 29 | void (*err_handler)(struct sk_buff *skb, u32 info); 30 | }; 31 | 32 | int gre_add_protocol(const struct gre_protocol *proto, u8 version); 33 | int gre_del_protocol(const struct gre_protocol *proto, u8 version); 34 | 35 | struct net_device *gretap_fb_dev_create(struct net *net, const char *name, 36 | u8 name_assign_type); 37 | int gre_parse_header(struct sk_buff *skb, struct tnl_ptk_info *tpi, 38 | bool *csum_err, __be16 proto, int nhs); 39 | 40 | static inline bool netif_is_gretap(const struct net_device *dev) 41 | { 42 | return dev->rtnl_link_ops && 43 | !strcmp(dev->rtnl_link_ops->kind, "gretap"); 44 | } 45 | 46 | static inline bool netif_is_ip6gretap(const struct net_device *dev) 47 | { 48 | return dev->rtnl_link_ops && 49 | !strcmp(dev->rtnl_link_ops->kind, "ip6gretap"); 50 | } 51 | 52 | static inline int gre_calc_hlen(__be16 o_flags) 53 | { 54 | int addend = 4; 55 | 56 | if (o_flags & TUNNEL_CSUM) 57 | addend += 4; 58 | if (o_flags & TUNNEL_KEY) 59 | addend += 4; 60 | if (o_flags & TUNNEL_SEQ) 61 | addend += 4; 62 | return addend; 63 | } 64 | 65 | static inline __be16 gre_flags_to_tnl_flags(__be16 flags) 66 | { 67 | __be16 tflags = 0; 68 | 69 | if (flags & GRE_CSUM) 70 | tflags |= TUNNEL_CSUM; 71 | if (flags & GRE_ROUTING) 72 | tflags |= TUNNEL_ROUTING; 73 | if (flags & GRE_KEY) 74 | tflags |= TUNNEL_KEY; 75 | if (flags & GRE_SEQ) 76 | tflags |= TUNNEL_SEQ; 77 | if (flags & GRE_STRICT) 78 | tflags |= TUNNEL_STRICT; 79 | if (flags & GRE_REC) 80 | tflags |= TUNNEL_REC; 81 | if (flags & GRE_VERSION) 82 | tflags |= TUNNEL_VERSION; 83 | 84 | return tflags; 85 | } 86 | 87 | static inline __be16 gre_tnl_flags_to_gre_flags(__be16 tflags) 88 | { 89 | __be16 flags = 0; 90 | 91 | if (tflags & TUNNEL_CSUM) 92 | flags |= GRE_CSUM; 93 | if (tflags & TUNNEL_ROUTING) 94 | flags |= GRE_ROUTING; 95 | if (tflags & TUNNEL_KEY) 96 | flags |= GRE_KEY; 97 | if (tflags & TUNNEL_SEQ) 98 | flags |= GRE_SEQ; 99 | if (tflags & TUNNEL_STRICT) 100 | flags |= GRE_STRICT; 101 | if (tflags & TUNNEL_REC) 102 | flags |= GRE_REC; 103 | if (tflags & TUNNEL_VERSION) 104 | flags |= GRE_VERSION; 105 | 106 | return flags; 107 | } 108 | 109 | static inline __sum16 gre_checksum(struct sk_buff *skb) 110 | { 111 | __wsum csum; 112 | 113 | if (skb->ip_summed == CHECKSUM_PARTIAL) 114 | csum = lco_csum(skb); 115 | else 116 | csum = skb_checksum(skb, 0, skb->len, 0); 117 | return csum_fold(csum); 118 | } 119 | 120 | static inline void gre_build_header(struct sk_buff *skb, int hdr_len, 121 | __be16 flags, __be16 proto, 122 | __be32 key, __be32 seq) 123 | { 124 | struct gre_base_hdr *greh; 125 | 126 | skb_push(skb, hdr_len); 127 | 128 | skb_set_inner_protocol(skb, proto); 129 | skb_reset_transport_header(skb); 130 | greh = (struct gre_base_hdr *)skb->data; 131 | greh->flags = gre_tnl_flags_to_gre_flags(flags); 132 | greh->protocol = proto; 133 | 134 | if (flags & (TUNNEL_KEY | TUNNEL_CSUM | TUNNEL_SEQ)) { 135 | __be32 *ptr = (__be32 *)(((u8 *)greh) + hdr_len - 4); 136 | 137 | if (flags & TUNNEL_SEQ) { 138 | *ptr = seq; 139 | ptr--; 140 | } 141 | if (flags & TUNNEL_KEY) { 142 | *ptr = key; 143 | ptr--; 144 | } 145 | if (flags & TUNNEL_CSUM && 146 | !(skb_shinfo(skb)->gso_type & 147 | (SKB_GSO_GRE | SKB_GSO_GRE_CSUM))) { 148 | *ptr = 0; 149 | *(__sum16 *)ptr = gre_checksum(skb); 150 | } 151 | } 152 | } 153 | 154 | #endif 155 | -------------------------------------------------------------------------------- /out-of-tree-5.6.x/gre_demux-5.6.0.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * GRE over IPv4 demultiplexer driver 4 | * 5 | * Authors: Dmitry Kozlov (xeb@mail.ru) 6 | */ 7 | 8 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | static const struct gre_protocol __rcu *gre_proto[GREPROTO_MAX] __read_mostly; 30 | 31 | int gre_add_protocol(const struct gre_protocol *proto, u8 version) 32 | { 33 | if (version >= GREPROTO_MAX) 34 | return -EINVAL; 35 | 36 | return (cmpxchg((const struct gre_protocol **)&gre_proto[version], NULL, proto) == NULL) ? 37 | 0 : -EBUSY; 38 | } 39 | EXPORT_SYMBOL_GPL(gre_add_protocol); 40 | 41 | int gre_del_protocol(const struct gre_protocol *proto, u8 version) 42 | { 43 | int ret; 44 | 45 | if (version >= GREPROTO_MAX) 46 | return -EINVAL; 47 | 48 | ret = (cmpxchg((const struct gre_protocol **)&gre_proto[version], proto, NULL) == proto) ? 49 | 0 : -EBUSY; 50 | 51 | if (ret) 52 | return ret; 53 | 54 | synchronize_rcu(); 55 | return 0; 56 | } 57 | EXPORT_SYMBOL_GPL(gre_del_protocol); 58 | 59 | /* Fills in tpi and returns header length to be pulled. 60 | * Note that caller must use pskb_may_pull() before pulling GRE header. 61 | */ 62 | int gre_parse_header(struct sk_buff *skb, struct tnl_ptk_info *tpi, 63 | bool *csum_err, __be16 proto, int nhs) 64 | { 65 | const struct gre_base_hdr *greh; 66 | __be32 *options; 67 | int hdr_len; 68 | 69 | if (unlikely(!pskb_may_pull(skb, nhs + sizeof(struct gre_base_hdr)))) 70 | return -EINVAL; 71 | 72 | greh = (struct gre_base_hdr *)(skb->data + nhs); 73 | if (unlikely(greh->flags & (GRE_VERSION | GRE_ROUTING))) 74 | return -EINVAL; 75 | 76 | tpi->flags = gre_flags_to_tnl_flags(greh->flags); 77 | hdr_len = gre_calc_hlen(tpi->flags); 78 | 79 | if (!pskb_may_pull(skb, nhs + hdr_len)) 80 | return -EINVAL; 81 | 82 | greh = (struct gre_base_hdr *)(skb->data + nhs); 83 | tpi->proto = greh->protocol; 84 | 85 | options = (__be32 *)(greh + 1); 86 | if (greh->flags & GRE_CSUM) { 87 | if (!skb_checksum_simple_validate(skb)) { 88 | skb_checksum_try_convert(skb, IPPROTO_GRE, 89 | null_compute_pseudo); 90 | } else if (csum_err) { 91 | *csum_err = true; 92 | return -EINVAL; 93 | } 94 | 95 | options++; 96 | } 97 | 98 | if (greh->flags & GRE_KEY) { 99 | tpi->key = *options; 100 | options++; 101 | } else { 102 | tpi->key = 0; 103 | } 104 | if (unlikely(greh->flags & GRE_SEQ)) { 105 | tpi->seq = *options; 106 | options++; 107 | } else { 108 | tpi->seq = 0; 109 | } 110 | /* WCCP version 1 and 2 protocol decoding. 111 | * - Change protocol to IPv4/IPv6 112 | * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header 113 | */ 114 | if (greh->flags == 0 && tpi->proto == htons(ETH_P_WCCP)) { 115 | u8 _val, *val; 116 | 117 | val = skb_header_pointer(skb, nhs + hdr_len, 118 | sizeof(_val), &_val); 119 | if (!val) 120 | return -EINVAL; 121 | tpi->proto = proto; 122 | if ((*val & 0xF0) != 0x40) 123 | hdr_len += 4; 124 | } 125 | tpi->hdr_len = hdr_len; 126 | 127 | /* ERSPAN ver 1 and 2 protocol sets GRE key field 128 | * to 0 and sets the configured key in the 129 | * inner erspan header field 130 | */ 131 | if (greh->protocol == htons(ETH_P_ERSPAN) || 132 | greh->protocol == htons(ETH_P_ERSPAN2)) { 133 | struct erspan_base_hdr *ershdr; 134 | 135 | if (!pskb_may_pull(skb, nhs + hdr_len + sizeof(*ershdr))) 136 | return -EINVAL; 137 | 138 | ershdr = (struct erspan_base_hdr *)(skb->data + nhs + hdr_len); 139 | tpi->key = cpu_to_be32(get_session_id(ershdr)); 140 | } 141 | 142 | return hdr_len; 143 | } 144 | EXPORT_SYMBOL(gre_parse_header); 145 | 146 | static int gre_rcv(struct sk_buff *skb) 147 | { 148 | const struct gre_protocol *proto; 149 | u8 ver; 150 | int ret; 151 | 152 | if (!pskb_may_pull(skb, 12)) 153 | goto drop; 154 | 155 | ver = skb->data[1]&0x7f; 156 | if (ver >= GREPROTO_MAX) 157 | goto drop; 158 | 159 | rcu_read_lock(); 160 | proto = rcu_dereference(gre_proto[ver]); 161 | if (!proto || !proto->handler) 162 | goto drop_unlock; 163 | ret = proto->handler(skb); 164 | rcu_read_unlock(); 165 | return ret; 166 | 167 | drop_unlock: 168 | rcu_read_unlock(); 169 | drop: 170 | kfree_skb(skb); 171 | return NET_RX_DROP; 172 | } 173 | 174 | static int gre_err(struct sk_buff *skb, u32 info) 175 | { 176 | const struct gre_protocol *proto; 177 | const struct iphdr *iph = (const struct iphdr *)skb->data; 178 | u8 ver = skb->data[(iph->ihl<<2) + 1]&0x7f; 179 | int err = 0; 180 | 181 | if (ver >= GREPROTO_MAX) 182 | return -EINVAL; 183 | 184 | rcu_read_lock(); 185 | proto = rcu_dereference(gre_proto[ver]); 186 | if (proto && proto->err_handler) 187 | proto->err_handler(skb, info); 188 | else 189 | err = -EPROTONOSUPPORT; 190 | rcu_read_unlock(); 191 | 192 | return err; 193 | } 194 | 195 | static const struct net_protocol net_gre_protocol = { 196 | .handler = gre_rcv, 197 | .err_handler = gre_err, 198 | .netns_ok = 1, 199 | }; 200 | 201 | static int __init gre_init(void) 202 | { 203 | pr_info("GRE over IPv4 demultiplexor driver\n"); 204 | 205 | if (inet_add_protocol(&net_gre_protocol, IPPROTO_GRE) < 0) { 206 | pr_err("can't add protocol\n"); 207 | return -EAGAIN; 208 | } 209 | return 0; 210 | } 211 | 212 | static void __exit gre_exit(void) 213 | { 214 | inet_del_protocol(&net_gre_protocol, IPPROTO_GRE); 215 | } 216 | 217 | module_init(gre_init); 218 | module_exit(gre_exit); 219 | 220 | MODULE_DESCRIPTION("GRE over IPv4 demultiplexer driver"); 221 | MODULE_AUTHOR("D. Kozlov (xeb@mail.ru)"); 222 | MODULE_LICENSE("GPL"); 223 | -------------------------------------------------------------------------------- /out-of-tree-5.7.x: -------------------------------------------------------------------------------- 1 | out-of-tree-5.6.x -------------------------------------------------------------------------------- /out-of-tree-6.0.x/Makefile: -------------------------------------------------------------------------------- 1 | ifneq ($(KERNELRELEASE),) 2 | # ugly and dirty hack to avoid patching system's kernel headers 3 | ccflags-y += "-DGREPROTO_NONSTD_EOIP=0x80" 4 | ccflags-y += "-DGREPROTO_NONSTD_MAX=0x81" 5 | ccflags-y += "-DGREPROTO_NONSTD_BASE=0x80" 6 | obj-m := eoip.o 7 | obj-m += gre.o 8 | else 9 | KDIR ?= /lib/modules/`uname -r`/build 10 | default: eoip.c gre.c gre.h 11 | @$(MAKE) -C $(KDIR) M=$$PWD 12 | eoip.c: ../kernel-patch/kernel-6.0.0-eoip.patch 13 | @patch -p3 < $< 14 | gre.c gre.h: ../kernel-patch/kernel-6.0.0-eoip-gre-demux.patch 15 | @if [ -f /lib/modules/`uname -r`/build/net/ipv4/gre.c ]; then echo found running kernel version of gre.c; cp /lib/modules/`uname -r`/build/net/ipv4/gre_demux.c gre_demux.c; else echo using 6.0.0 version of gre_demux.c; cp gre_demux-6.0.0.c gre_demux.c; fi 16 | @if [ -f /lib/modules/`uname -r`/build/include/net/gre.h ]; then echo found running kernel version of gre.h; cp /lib/modules/`uname -r`/build/include/net/gre.h gre.h; else echo using 6.0.0 version of gre.h; cp gre-6.0.0.h gre.h; fi 17 | @patch -p3 < $< 18 | @cp gre_demux.c gre.c 19 | clean: 20 | @rm -f gre_demux.c gre.c gre.h eoip.c *.orig *.rej 21 | @$(MAKE) -C $(KDIR) M=$$PWD clean 22 | install modules_install: 23 | @$(MAKE) -C $(KDIR) M=$$PWD modules_install 24 | endif 25 | -------------------------------------------------------------------------------- /out-of-tree-6.0.x/gre-6.0.0.h: -------------------------------------------------------------------------------- 1 | ../out-of-tree-5.17.x/gre-5.17.0.h -------------------------------------------------------------------------------- /out-of-tree-6.0.x/gre_demux-6.0.0.c: -------------------------------------------------------------------------------- 1 | ../out-of-tree-5.17.x/gre_demux-5.17.0.c -------------------------------------------------------------------------------- /out-of-tree-6.1.x/Makefile: -------------------------------------------------------------------------------- 1 | ifneq ($(KERNELRELEASE),) 2 | # ugly and dirty hack to avoid patching system's kernel headers 3 | ccflags-y += "-DGREPROTO_NONSTD_EOIP=0x80" 4 | ccflags-y += "-DGREPROTO_NONSTD_MAX=0x81" 5 | ccflags-y += "-DGREPROTO_NONSTD_BASE=0x80" 6 | obj-m := eoip.o 7 | obj-m += gre.o 8 | else 9 | KDIR ?= /lib/modules/`uname -r`/build 10 | default: eoip.c gre.c gre.h 11 | @$(MAKE) -C $(KDIR) M=$$PWD 12 | eoip.c: ../kernel-patch/kernel-6.1.0-eoip.patch 13 | @patch -p3 < $< 14 | gre.c gre.h: ../kernel-patch/kernel-6.1.0-eoip-gre-demux.patch 15 | @if [ -f /lib/modules/`uname -r`/build/net/ipv4/gre.c ]; then echo found running kernel version of gre.c; cp /lib/modules/`uname -r`/build/net/ipv4/gre_demux.c gre_demux.c; else echo using 6.1.0 version of gre_demux.c; cp gre_demux-6.1.0.c gre_demux.c; fi 16 | @if [ -f /lib/modules/`uname -r`/build/include/net/gre.h ]; then echo found running kernel version of gre.h; cp /lib/modules/`uname -r`/build/include/net/gre.h gre.h; else echo using 6.1.0 version of gre.h; cp gre-6.1.0.h gre.h; fi 17 | @patch -p3 < $< 18 | @cp gre_demux.c gre.c 19 | clean: 20 | @rm -f gre_demux.c gre.c gre.h eoip.c *.orig *.rej 21 | @$(MAKE) -C $(KDIR) M=$$PWD clean 22 | install modules_install: 23 | @$(MAKE) -C $(KDIR) M=$$PWD modules_install 24 | endif 25 | -------------------------------------------------------------------------------- /out-of-tree-6.1.x/gre-6.1.0.h: -------------------------------------------------------------------------------- 1 | ../out-of-tree-6.0.x/gre-6.0.0.h -------------------------------------------------------------------------------- /out-of-tree-6.1.x/gre_demux-6.1.0.c: -------------------------------------------------------------------------------- 1 | ../out-of-tree-6.0.x/gre_demux-6.0.0.c -------------------------------------------------------------------------------- /out-of-tree-6.12.x/Makefile: -------------------------------------------------------------------------------- 1 | ifneq ($(KERNELRELEASE),) 2 | # ugly and dirty hack to avoid patching system's kernel headers 3 | ccflags-y += "-DGREPROTO_NONSTD_EOIP=0x80" 4 | ccflags-y += "-DGREPROTO_NONSTD_MAX=0x81" 5 | ccflags-y += "-DGREPROTO_NONSTD_BASE=0x80" 6 | obj-m := eoip.o 7 | obj-m += gre.o 8 | else 9 | KDIR ?= /lib/modules/`uname -r`/build 10 | default: eoip.c gre.c gre.h 11 | @$(MAKE) -C $(KDIR) M=$$PWD 12 | eoip.c: ../kernel-patch/kernel-6.12.0-eoip.patch 13 | @patch -p3 < $< 14 | gre.c gre.h: ../kernel-patch/kernel-6.12.0-eoip-gre-demux.patch 15 | @if [ -f /lib/modules/`uname -r`/build/net/ipv4/gre.c ]; then echo found running kernel version of gre.c; cp /lib/modules/`uname -r`/build/net/ipv4/gre_demux.c gre_demux.c; else echo using 6.12.0 version of gre_demux.c; cp gre_demux-6.12.0.c gre_demux.c; fi 16 | @if [ -f /lib/modules/`uname -r`/build/include/net/gre.h ]; then echo found running kernel version of gre.h; cp /lib/modules/`uname -r`/build/include/net/gre.h gre.h; else echo using 6.12.0 version of gre.h; cp gre-6.12.0.h gre.h; fi 17 | @patch -p3 < $< 18 | @cp gre_demux.c gre.c 19 | clean: 20 | @rm -f gre_demux.c gre.c gre.h eoip.c *.orig *.rej 21 | @$(MAKE) -C $(KDIR) M=$$PWD clean 22 | install modules_install: 23 | @$(MAKE) -C $(KDIR) M=$$PWD modules_install 24 | endif 25 | -------------------------------------------------------------------------------- /out-of-tree-6.12.x/gre-6.12.0.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | #ifndef __LINUX_GRE_H 3 | #define __LINUX_GRE_H 4 | 5 | #include 6 | #include 7 | 8 | struct gre_base_hdr { 9 | __be16 flags; 10 | __be16 protocol; 11 | } __packed; 12 | 13 | struct gre_full_hdr { 14 | struct gre_base_hdr fixed_header; 15 | __be16 csum; 16 | __be16 reserved1; 17 | __be32 key; 18 | __be32 seq; 19 | } __packed; 20 | #define GRE_HEADER_SECTION 4 21 | 22 | #define GREPROTO_CISCO 0 23 | #define GREPROTO_PPTP 1 24 | #define GREPROTO_MAX 2 25 | #define GRE_IP_PROTO_MAX 2 26 | 27 | struct gre_protocol { 28 | int (*handler)(struct sk_buff *skb); 29 | void (*err_handler)(struct sk_buff *skb, u32 info); 30 | }; 31 | 32 | int gre_add_protocol(const struct gre_protocol *proto, u8 version); 33 | int gre_del_protocol(const struct gre_protocol *proto, u8 version); 34 | 35 | struct net_device *gretap_fb_dev_create(struct net *net, const char *name, 36 | u8 name_assign_type); 37 | int gre_parse_header(struct sk_buff *skb, struct tnl_ptk_info *tpi, 38 | bool *csum_err, __be16 proto, int nhs); 39 | 40 | static inline bool netif_is_gretap(const struct net_device *dev) 41 | { 42 | return dev->rtnl_link_ops && 43 | !strcmp(dev->rtnl_link_ops->kind, "gretap"); 44 | } 45 | 46 | static inline bool netif_is_ip6gretap(const struct net_device *dev) 47 | { 48 | return dev->rtnl_link_ops && 49 | !strcmp(dev->rtnl_link_ops->kind, "ip6gretap"); 50 | } 51 | 52 | static inline int gre_calc_hlen(const unsigned long *o_flags) 53 | { 54 | int addend = 4; 55 | 56 | if (test_bit(IP_TUNNEL_CSUM_BIT, o_flags)) 57 | addend += 4; 58 | if (test_bit(IP_TUNNEL_KEY_BIT, o_flags)) 59 | addend += 4; 60 | if (test_bit(IP_TUNNEL_SEQ_BIT, o_flags)) 61 | addend += 4; 62 | return addend; 63 | } 64 | 65 | static inline void gre_flags_to_tnl_flags(unsigned long *dst, __be16 flags) 66 | { 67 | IP_TUNNEL_DECLARE_FLAGS(res) = { }; 68 | 69 | __assign_bit(IP_TUNNEL_CSUM_BIT, res, flags & GRE_CSUM); 70 | __assign_bit(IP_TUNNEL_ROUTING_BIT, res, flags & GRE_ROUTING); 71 | __assign_bit(IP_TUNNEL_KEY_BIT, res, flags & GRE_KEY); 72 | __assign_bit(IP_TUNNEL_SEQ_BIT, res, flags & GRE_SEQ); 73 | __assign_bit(IP_TUNNEL_STRICT_BIT, res, flags & GRE_STRICT); 74 | __assign_bit(IP_TUNNEL_REC_BIT, res, flags & GRE_REC); 75 | __assign_bit(IP_TUNNEL_VERSION_BIT, res, flags & GRE_VERSION); 76 | 77 | ip_tunnel_flags_copy(dst, res); 78 | } 79 | 80 | static inline __be16 gre_tnl_flags_to_gre_flags(const unsigned long *tflags) 81 | { 82 | __be16 flags = 0; 83 | 84 | if (test_bit(IP_TUNNEL_CSUM_BIT, tflags)) 85 | flags |= GRE_CSUM; 86 | if (test_bit(IP_TUNNEL_ROUTING_BIT, tflags)) 87 | flags |= GRE_ROUTING; 88 | if (test_bit(IP_TUNNEL_KEY_BIT, tflags)) 89 | flags |= GRE_KEY; 90 | if (test_bit(IP_TUNNEL_SEQ_BIT, tflags)) 91 | flags |= GRE_SEQ; 92 | if (test_bit(IP_TUNNEL_STRICT_BIT, tflags)) 93 | flags |= GRE_STRICT; 94 | if (test_bit(IP_TUNNEL_REC_BIT, tflags)) 95 | flags |= GRE_REC; 96 | if (test_bit(IP_TUNNEL_VERSION_BIT, tflags)) 97 | flags |= GRE_VERSION; 98 | 99 | return flags; 100 | } 101 | 102 | static inline void gre_build_header(struct sk_buff *skb, int hdr_len, 103 | const unsigned long *flags, __be16 proto, 104 | __be32 key, __be32 seq) 105 | { 106 | IP_TUNNEL_DECLARE_FLAGS(cond) = { }; 107 | struct gre_base_hdr *greh; 108 | 109 | skb_push(skb, hdr_len); 110 | 111 | skb_set_inner_protocol(skb, proto); 112 | skb_reset_transport_header(skb); 113 | greh = (struct gre_base_hdr *)skb->data; 114 | greh->flags = gre_tnl_flags_to_gre_flags(flags); 115 | greh->protocol = proto; 116 | 117 | __set_bit(IP_TUNNEL_KEY_BIT, cond); 118 | __set_bit(IP_TUNNEL_CSUM_BIT, cond); 119 | __set_bit(IP_TUNNEL_SEQ_BIT, cond); 120 | 121 | if (ip_tunnel_flags_intersect(flags, cond)) { 122 | __be32 *ptr = (__be32 *)(((u8 *)greh) + hdr_len - 4); 123 | 124 | if (test_bit(IP_TUNNEL_SEQ_BIT, flags)) { 125 | *ptr = seq; 126 | ptr--; 127 | } 128 | if (test_bit(IP_TUNNEL_KEY_BIT, flags)) { 129 | *ptr = key; 130 | ptr--; 131 | } 132 | if (test_bit(IP_TUNNEL_CSUM_BIT, flags) && 133 | !(skb_shinfo(skb)->gso_type & 134 | (SKB_GSO_GRE | SKB_GSO_GRE_CSUM))) { 135 | *ptr = 0; 136 | if (skb->ip_summed == CHECKSUM_PARTIAL) { 137 | *(__sum16 *)ptr = csum_fold(lco_csum(skb)); 138 | } else { 139 | skb->ip_summed = CHECKSUM_PARTIAL; 140 | skb->csum_start = skb_transport_header(skb) - skb->head; 141 | skb->csum_offset = sizeof(*greh); 142 | } 143 | } 144 | } 145 | } 146 | 147 | #endif 148 | -------------------------------------------------------------------------------- /out-of-tree-6.12.x/gre_demux-6.12.0.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * GRE over IPv4 demultiplexer driver 4 | * 5 | * Authors: Dmitry Kozlov (xeb@mail.ru) 6 | */ 7 | 8 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | static const struct gre_protocol __rcu *gre_proto[GREPROTO_MAX] __read_mostly; 30 | 31 | int gre_add_protocol(const struct gre_protocol *proto, u8 version) 32 | { 33 | if (version >= GREPROTO_MAX) 34 | return -EINVAL; 35 | 36 | return (cmpxchg((const struct gre_protocol **)&gre_proto[version], NULL, proto) == NULL) ? 37 | 0 : -EBUSY; 38 | } 39 | EXPORT_SYMBOL_GPL(gre_add_protocol); 40 | 41 | int gre_del_protocol(const struct gre_protocol *proto, u8 version) 42 | { 43 | int ret; 44 | 45 | if (version >= GREPROTO_MAX) 46 | return -EINVAL; 47 | 48 | ret = (cmpxchg((const struct gre_protocol **)&gre_proto[version], proto, NULL) == proto) ? 49 | 0 : -EBUSY; 50 | 51 | if (ret) 52 | return ret; 53 | 54 | synchronize_rcu(); 55 | return 0; 56 | } 57 | EXPORT_SYMBOL_GPL(gre_del_protocol); 58 | 59 | /* Fills in tpi and returns header length to be pulled. 60 | * Note that caller must use pskb_may_pull() before pulling GRE header. 61 | */ 62 | int gre_parse_header(struct sk_buff *skb, struct tnl_ptk_info *tpi, 63 | bool *csum_err, __be16 proto, int nhs) 64 | { 65 | const struct gre_base_hdr *greh; 66 | __be32 *options; 67 | int hdr_len; 68 | 69 | if (unlikely(!pskb_may_pull(skb, nhs + sizeof(struct gre_base_hdr)))) 70 | return -EINVAL; 71 | 72 | greh = (struct gre_base_hdr *)(skb->data + nhs); 73 | if (unlikely(greh->flags & (GRE_VERSION | GRE_ROUTING))) 74 | return -EINVAL; 75 | 76 | gre_flags_to_tnl_flags(tpi->flags, greh->flags); 77 | hdr_len = gre_calc_hlen(tpi->flags); 78 | 79 | if (!pskb_may_pull(skb, nhs + hdr_len)) 80 | return -EINVAL; 81 | 82 | greh = (struct gre_base_hdr *)(skb->data + nhs); 83 | tpi->proto = greh->protocol; 84 | 85 | options = (__be32 *)(greh + 1); 86 | if (greh->flags & GRE_CSUM) { 87 | if (!skb_checksum_simple_validate(skb)) { 88 | skb_checksum_try_convert(skb, IPPROTO_GRE, 89 | null_compute_pseudo); 90 | } else if (csum_err) { 91 | *csum_err = true; 92 | return -EINVAL; 93 | } 94 | 95 | options++; 96 | } 97 | 98 | if (greh->flags & GRE_KEY) { 99 | tpi->key = *options; 100 | options++; 101 | } else { 102 | tpi->key = 0; 103 | } 104 | if (unlikely(greh->flags & GRE_SEQ)) { 105 | tpi->seq = *options; 106 | options++; 107 | } else { 108 | tpi->seq = 0; 109 | } 110 | /* WCCP version 1 and 2 protocol decoding. 111 | * - Change protocol to IPv4/IPv6 112 | * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header 113 | */ 114 | if (greh->flags == 0 && tpi->proto == htons(ETH_P_WCCP)) { 115 | u8 _val, *val; 116 | 117 | val = skb_header_pointer(skb, nhs + hdr_len, 118 | sizeof(_val), &_val); 119 | if (!val) 120 | return -EINVAL; 121 | tpi->proto = proto; 122 | if ((*val & 0xF0) != 0x40) 123 | hdr_len += 4; 124 | } 125 | tpi->hdr_len = hdr_len; 126 | 127 | /* ERSPAN ver 1 and 2 protocol sets GRE key field 128 | * to 0 and sets the configured key in the 129 | * inner erspan header field 130 | */ 131 | if ((greh->protocol == htons(ETH_P_ERSPAN) && hdr_len != 4) || 132 | greh->protocol == htons(ETH_P_ERSPAN2)) { 133 | struct erspan_base_hdr *ershdr; 134 | 135 | if (!pskb_may_pull(skb, nhs + hdr_len + sizeof(*ershdr))) 136 | return -EINVAL; 137 | 138 | ershdr = (struct erspan_base_hdr *)(skb->data + nhs + hdr_len); 139 | tpi->key = cpu_to_be32(get_session_id(ershdr)); 140 | } 141 | 142 | return hdr_len; 143 | } 144 | EXPORT_SYMBOL(gre_parse_header); 145 | 146 | static int gre_rcv(struct sk_buff *skb) 147 | { 148 | const struct gre_protocol *proto; 149 | u8 ver; 150 | int ret; 151 | 152 | if (!pskb_may_pull(skb, 12)) 153 | goto drop; 154 | 155 | ver = skb->data[1]&0x7f; 156 | if (ver >= GREPROTO_MAX) 157 | goto drop; 158 | 159 | rcu_read_lock(); 160 | proto = rcu_dereference(gre_proto[ver]); 161 | if (!proto || !proto->handler) 162 | goto drop_unlock; 163 | ret = proto->handler(skb); 164 | rcu_read_unlock(); 165 | return ret; 166 | 167 | drop_unlock: 168 | rcu_read_unlock(); 169 | drop: 170 | kfree_skb(skb); 171 | return NET_RX_DROP; 172 | } 173 | 174 | static int gre_err(struct sk_buff *skb, u32 info) 175 | { 176 | const struct gre_protocol *proto; 177 | const struct iphdr *iph = (const struct iphdr *)skb->data; 178 | u8 ver = skb->data[(iph->ihl<<2) + 1]&0x7f; 179 | int err = 0; 180 | 181 | if (ver >= GREPROTO_MAX) 182 | return -EINVAL; 183 | 184 | rcu_read_lock(); 185 | proto = rcu_dereference(gre_proto[ver]); 186 | if (proto && proto->err_handler) 187 | proto->err_handler(skb, info); 188 | else 189 | err = -EPROTONOSUPPORT; 190 | rcu_read_unlock(); 191 | 192 | return err; 193 | } 194 | 195 | static const struct net_protocol net_gre_protocol = { 196 | .handler = gre_rcv, 197 | .err_handler = gre_err, 198 | }; 199 | 200 | static int __init gre_init(void) 201 | { 202 | pr_info("GRE over IPv4 demultiplexor driver\n"); 203 | 204 | if (inet_add_protocol(&net_gre_protocol, IPPROTO_GRE) < 0) { 205 | pr_err("can't add protocol\n"); 206 | return -EAGAIN; 207 | } 208 | return 0; 209 | } 210 | 211 | static void __exit gre_exit(void) 212 | { 213 | inet_del_protocol(&net_gre_protocol, IPPROTO_GRE); 214 | } 215 | 216 | module_init(gre_init); 217 | module_exit(gre_exit); 218 | 219 | MODULE_DESCRIPTION("GRE over IPv4 demultiplexer driver"); 220 | MODULE_AUTHOR("D. Kozlov "); 221 | MODULE_LICENSE("GPL"); 222 | -------------------------------------------------------------------------------- /out-of-tree-6.4.x: -------------------------------------------------------------------------------- 1 | out-of-tree-6.1.x -------------------------------------------------------------------------------- /out-of-tree-6.6.x: -------------------------------------------------------------------------------- 1 | out-of-tree-6.4.x -------------------------------------------------------------------------------- /out-of-tree-6.8.x/Makefile: -------------------------------------------------------------------------------- 1 | ifneq ($(KERNELRELEASE),) 2 | # ugly and dirty hack to avoid patching system's kernel headers 3 | ccflags-y += "-DGREPROTO_NONSTD_EOIP=0x80" 4 | ccflags-y += "-DGREPROTO_NONSTD_MAX=0x81" 5 | ccflags-y += "-DGREPROTO_NONSTD_BASE=0x80" 6 | obj-m := eoip.o 7 | obj-m += gre.o 8 | else 9 | KDIR ?= /lib/modules/`uname -r`/build 10 | default: eoip.c gre.c gre.h 11 | @$(MAKE) -C $(KDIR) M=$$PWD 12 | eoip.c: ../kernel-patch/kernel-6.8.0-eoip.patch 13 | @patch -p3 < $< 14 | gre.c gre.h: ../kernel-patch/kernel-6.8.0-eoip-gre-demux.patch 15 | @if [ -f /lib/modules/`uname -r`/build/net/ipv4/gre.c ]; then echo found running kernel version of gre.c; cp /lib/modules/`uname -r`/build/net/ipv4/gre_demux.c gre_demux.c; else echo using 6.8.0 version of gre_demux.c; cp gre_demux-6.8.0.c gre_demux.c; fi 16 | @if [ -f /lib/modules/`uname -r`/build/include/net/gre.h ]; then echo found running kernel version of gre.h; cp /lib/modules/`uname -r`/build/include/net/gre.h gre.h; else echo using 6.8.0 version of gre.h; cp gre-6.8.0.h gre.h; fi 17 | @patch -p3 < $< 18 | @cp gre_demux.c gre.c 19 | clean: 20 | @rm -f gre_demux.c gre.c gre.h eoip.c *.orig *.rej 21 | @$(MAKE) -C $(KDIR) M=$$PWD clean 22 | install modules_install: 23 | @$(MAKE) -C $(KDIR) M=$$PWD modules_install 24 | endif 25 | -------------------------------------------------------------------------------- /out-of-tree-6.8.x/gre-6.8.0.h: -------------------------------------------------------------------------------- 1 | ../out-of-tree-6.1.x/gre-6.1.0.h -------------------------------------------------------------------------------- /out-of-tree-6.8.x/gre_demux-6.8.0.c: -------------------------------------------------------------------------------- 1 | ../out-of-tree-6.1.x/gre_demux-6.1.0.c -------------------------------------------------------------------------------- /version.h: -------------------------------------------------------------------------------- 1 | #ifndef ___EOIP_VERSION_H___ 2 | #define ___EOIP_VERSION_H___ 3 | 4 | #define EOIP_VERSION "1.4" 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /version.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | BASEDIR=$(dirname "$0") 4 | 5 | sed -n 's/^#define.*EOIP_VERSION.*"\(.*\)".*/\1/p' "$BASEDIR"/version.h 6 | --------------------------------------------------------------------------------