├── .gitignore ├── COPYING ├── Changes ├── FAQ ├── INSTALL ├── Makefile ├── README.md ├── TODO ├── atropos.c ├── configs ├── vrrp ├── vrrp.service └── vrrpd │ ├── Backup.sh │ ├── Master.sh │ ├── startup.sh │ └── vrrp_on.sh ├── doc ├── draft-ietf-vrrp-spec-v2-05.txt ├── draft-jou-duplicate-ip-address-02.txt ├── principe-Vrrp1.jpg ├── principe-Vrrp2.jpg └── rfc2338.txt.vrrp ├── install.sh ├── ipaddr.c ├── ipaddr.h ├── libnetlink.c ├── libnetlink.h ├── ll_map.c ├── proto.h ├── route.generic ├── scott_example ├── vrrpd.8 ├── vrrpd.c └── vrrpd.h /.gitignore: -------------------------------------------------------------------------------- 1 | atropos 2 | vrrpd 3 | *.o 4 | core 5 | *~ 6 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 51 Franklin St, 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 Library 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 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 309 | 310 | 311 | Also add information on how to contact you by electronic and paper mail. 312 | 313 | If the program is interactive, make it output a short notice like this 314 | when it starts in an interactive mode: 315 | 316 | Gnomovision version 69, Copyright (C) year name of author 317 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 318 | This is free software, and you are welcome to redistribute it 319 | under certain conditions; type `show c' for details. 320 | 321 | The hypothetical commands `show w' and `show c' should show the appropriate 322 | parts of the General Public License. Of course, the commands you use may 323 | be called something other than `show w' and `show c'; they could even be 324 | mouse-clicks or menu items--whatever suits your program. 325 | 326 | You should also get your employer (if you work as a programmer) or your 327 | school, if any, to sign a "copyright disclaimer" for the program, if 328 | necessary. Here is a sample; alter the names: 329 | 330 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 331 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 332 | 333 | , 1 April 1989 334 | Ty Coon, President of Vice 335 | 336 | This General Public License does not permit incorporating your program into 337 | proprietary programs. If your program is a subroutine library, you may 338 | consider it more useful to permit linking proprietary applications with the 339 | library. If this is what you want to do, use the GNU Library General 340 | Public License instead of this License. 341 | -------------------------------------------------------------------------------- /Changes: -------------------------------------------------------------------------------- 1 | 23/01/2017 vrrpd 1.15 2 | 3 | Update vrrp interval (now default = 2 seconds) 4 | Virtual Mac disabled by default 5 | 6 | 07/01/2016 vrrpd 1.14 7 | 8 | Code cleaning 9 | Atropos: Improve information 10 | ARM (linux) compatibility 11 | Remove information files from tmp (can be changed now in vrrpd.h VRRP_PIDDIR_DFL) 12 | 13 | 23/06/2015 vrrpd 1.13 14 | 15 | Vrrpd security: Daemon cannot start with the same VRID than other - and different password - 16 | Fix: Remove all compile warnings. 17 | Atropos show all informations (status, time to live, etc) 18 | Fix: bad return to prompt (-h ou -V) 19 | 20 | 04/03/2015 vrrpd 1.12 21 | 22 | More information in log file (with atropos --state and syslog) 23 | Better control with VRRPD packets without any identification (like Arkoon FW) 24 | Minor fixes 25 | 26 | 10/09/2014 vrrpd 1.11 27 | 28 | Fix: The change in time cause the backup vrrp daemon to send vrrp advertisements - By charles savoie 29 | Fix: vrrpd cannot be invoked from python script - By charles savoie 30 | 31 | 03/02/2014 Vrrpd 1.10 32 | 33 | Two optional command line arguments (x,z) with value of priorities. 34 | If this arguments exists, calling signal SIGTTIN and SIGTTOU instead of increment/decrement 35 | priority of running process - By Ivan Zhiltsov - 36 | 37 | Fix: some minor bugs 38 | Cleaned source code 39 | Rewrite killvrrpd engine 40 | 41 | 10/09/2013 Vrrpd 1.9 42 | 43 | Fix: Minor bugs 44 | Atropos: Ability to change process priority (dynamically) 45 | 46 | 17/12/2012 Vrrpd 1.8 47 | 48 | Fix: bad behaviour with some link status 49 | Fix: Crash when trying to read non-readable config file 50 | 51 | 29/11/2012 Vrrpd 1.7 52 | 53 | Fix bad behaviour with slow network performance 54 | 55 | 13/06/2012 Vrrpd 1.6 56 | 57 | Code adaptation for Endian Firewall Community - Alain Abbas libertech.fr 58 | Fix bad behaviour with link status for some OS 59 | 60 | 15/02/2012 Vrrpd 1.5 61 | 62 | Optional subnet mask for the VIP address -> From Debian (Sylvain Vallerot) http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=235420 63 | Fix a bad behaviour with down/master script, if the shell script was frozen - for example with a sleep x command - Vrrpd was also blocked 64 | 65 | 23/01/2011 Vrrpd 1.4 66 | 67 | Magic packet - If you can't use virtual mac adress, Vrrpd send gratuitous ARP and it can also send magic packet from virtual to gateway 68 | VRRPD - Is now Compatible with vlan interfaces - with one vmac by vlan - 69 | 70 | 07/04/2011 Nouvelle version de Vrrpd (1.3): 71 | 72 | Modification permettant l'utilisation de Vrrpd sur des systèmes n'autorisant pas l'accès aux informations hardware des cartes réseaux - par exemple les systèmes de virtualisation - 73 | Dans ce cas Vrrpd fonctionne mais ne peut plus détecter la perte de link d'une interface. 74 | Pour la même raison l'option -n (pas de ma virtuelle) est obligatoire sur ce type de plate-forme 75 | 76 | 17/12/2010 Nouvelle version de Vrrpd (1.2): 77 | 78 | - Ajout du patch de Carlos Xavier, qui permet le changement de mac sans perte du link 79 | 80 | La bascule Vrrpd ne provoque plus la perte des routes. 81 | La perte de link ne provoque plus de bascules intempestives sur certains modèles de switchs 82 | 83 | 27/08/2008 Nouvelle version de Vrrpd (1.0): 84 | 85 | Rock solid ! 86 | 87 | - Correction d'un mauvais fonctionnement de l'application en cas de bascules successives rapides 88 | - Optimisation d'Atropos 89 | - Optimisation générale 90 | 91 | 19/10/2007 Nouvelle version de Vrrpd (0.9): 92 | 93 | - Correction d'un bug: 94 | 95 | Quand un processus Vrrpd est éteint par un kill (-15 ou killall) 96 | l'IP virtuelle disparaît bien, mais laisse la machine en l'état 97 | Maintenant le processus Vrrpd intercepte le signal et avant de mourir passe en backup 98 | 99 | De plus j'ai supprimé des lignes de log qui polluaient en affichant "short link down" lorsque une interface montait ou descendait 100 | 101 | 12/02/07 Nouvelle version de Vrrpd (0.8): 102 | 103 | - Optimisation globale de l'application (bascule plus rapide en mode Master) 104 | - Correction d'un bug potentiel lors du passage des paramètres pendant le démarrage de l'application. 105 | - Log plus simple et moins verbeux 106 | - Correction d'un bug empêchant le retour en mode Master lors de l'utilisation de VRRPD avec une seule interface réseau. 107 | 108 | 28/11/06 Nouvelle version de Vrrpd (0.7): 109 | 110 | - Atropos : Client pour vrrpd permettant de visualiser 111 | et de modifier l'état d'une machine. 112 | - Augmentation du temps de réaction Vrrpd en cas de coupure réseau (Link down) 113 | - Correction d'un mauvais fonctionnement concernant les gratuitous ARP 114 | 115 | 06/11/06 Nouvelle version de Vrrpd (0.6): 116 | 117 | Correction d'un mauvais fonctionnement de l'application après 118 | des bascules multiples (MASTER -> BACKUP -> MASTER -> BACKUP) 119 | 120 | 17/10/06 Nouvelle version de Vrrpd (0.5): 121 | 122 | Optimisation du comportement avec plus de trois interfaces par serveur (MAX 9). 123 | Réécriture du format de log. 124 | 125 | - Ajout d'un tag WARNING pour les situations de panne 126 | - Ajout d'un champ (vrrpd: VRRP ID 1 on eth0) permettant de suivre 127 | un processus. 128 | 129 | Oct 17 01:15:38 netfilter1 vrrpd: VRRP ID 1 on eth0: WARNING: Link down eth0 130 | Oct 17 01:15:38 netfilter1 vrrpd: VRRP ID 1 on eth0: going to Backup state 131 | Oct 17 01:15:38 netfilter1 vrrpd: VRRP ID 1 on eth0: Another vrrpd run with PID: 7277 my PID: 7275 132 | Oct 17 01:15:38 netfilter1 vrrpd: VRRP ID 1 on eth0: I ask : VRRPD PID: 7277 Backup state 133 | 134 | 21/09/06 Nouvelle version de Vrrpd (0.4): 135 | 136 | Gratuitous ARP sur les interfaces physiques à chaque changement 137 | d'état MASTER et SLAVE 138 | 139 | 08/09/06 Nouvelle version de Vrrpd (0.3): 140 | 141 | - Modification du format des logs, ajout d'un tag WARNING sur les motifs de pannes 142 | par ex: (Sep 21 17:43:49 src@Netfilter vrrpd: WARNING: Link down eth1) 143 | 144 | - Modification du comportement inter-processus: 145 | Dans la version précédente lors d'une panne, par exemple une interface Link down, 146 | tous les processus passaient en Backup, puis si les conditions étaient favorables certains 147 | essayaient de passer en STATE MASTER. Maintenant ils restent tous en STATE BACKUP dans l'attente 148 | du changement d'état de l'interface (retour en Link up) cela evite d'avoir deux liens en 149 | STATE MASTER lors de la remise en service. 150 | 151 | 27/06/06 Nouvelle version de Vrrpd (0.2): 152 | 153 | - Petit changement cosmétique dans les messages syslogs 154 | 155 | 04/06/06 Nouvelle version de Vrrpd (0.1): 156 | 157 | - Ajout d'une supervision, détection d'anomalie sur tous les processus permettant la gestion 158 | et la supervision d'état d'un serveur utilisant plusieurs interfaces réseaux. 159 | 160 | - Passage de commandes lors d'un changement d'état VRRP 161 | 162 | ----------------------------------------------------------- 163 | 0.4 - Sep 26th 2000 164 | - written a man(8) page 165 | - implemented the password authentication rfc2338.10.2 166 | (not tested because i have a single computer :) 167 | - change the state according to unix signal. USR1=be master, USR2=be backup 168 | pid stored in a file vrrpd_[IF]_[VRID].pid (e.g. vrrp_eth0_50.pid) 169 | WARNING: for guru only 170 | 171 | 0.3 - june 8th 2000 172 | - add -n option. if it is set, vrrpd doesnt handle the virtual mac address. 173 | It isnt compliant to the rfc. but in practice it work and allow to have 174 | several virtual groups per interface (workaround the kernel assumption 175 | 1 MAC per physical interface) 176 | - fix a compilation problem with glibc-2.1.1 or below, MSG_TRUNC is undefined. 177 | reported by Hannes R. Boehm 178 | 179 | 0.2 - may 18th 2000 180 | - knowledgable comment and bug fix from Hannes R. Boehm 181 | (VRRP_IS_BAD_PRIORITY, authentication field) 182 | - gratuitous arp for non-vrrp addresses when the master becomes backup 183 | - bug fix not to remove the primary address when the master is the address 184 | owner and become backup. 185 | - no more depends on 'ip' from iproute tools. now netlink is used directly 186 | to set/remove the ip addresses. 187 | 188 | 0.1 - may 14th 2000 189 | - release of the first version 190 | -------------------------------------------------------------------------------- /FAQ: -------------------------------------------------------------------------------- 1 | vrrpd is a deamon which support the VRRP v2 protocol as specified in rfc2338. 2 | 3 | ------------------------------------------------------------------- 4 | Introduction: 5 | 6 | Q. what is VRRPd ? 7 | vrrpd is an implementation of VRRPv2 as specified in rfc2338. It run 8 | in userspace for linux. 9 | 10 | Q. what is VRRP ? 11 | A. In short, VRRP is a protocol which elects a master server on a LAN and 12 | the master answers to a 'virtual ip address'. If it fails, a backup 13 | server takes over the ip address. 14 | 15 | A longuer answer in the rfc2338 abstract : 16 | "This memo defines the Virtual Router Redundancy Protocol (VRRP). 17 | VRRP specifies an election protocol that dynamically assigns 18 | responsibility for a virtual router to one of the VRRP routers on a 19 | LAN. The VRRP router controlling the IP address(es) associated with 20 | a virtual router is called the Master, and forwards packets sent to 21 | these IP addresses. The election process provides dynamic fail over 22 | in the forwarding responsibility should the Master become 23 | unavailable. This allows any of the virtual router IP addresses on 24 | the LAN to be used as the default first hop router by end-hosts. The 25 | advantage gained from using VRRP is a higher availability default 26 | path without requiring configuration of dynamic routing or router 27 | discovery protocols on every end-host." 28 | 29 | Copyright (C) The Internet Society (1998). All Rights Reserved. 30 | 31 | NOTE: the RFC keep talking about routers for historical reasons but the 32 | protocol isn't dedicated to routers and it can used it for any kind of 33 | server. 34 | 35 | ------------------------------------------------------------------- 36 | Configuration: 37 | 38 | Q. how can i set up the 'ip authentication header' ? 39 | A. Ip authentication header is the long name for AH (rfc2402) and is 40 | outside the scope of vrrpd. To have this protection, you should 41 | configure IPSec. 42 | 43 | Q. What are the required options to compiled in the kernel ? 44 | A. Set the following options: 45 | IP aliasing: to have several IP addresses per interface 46 | Kernel/User netlink socket: to communicate between the process 47 | and the kernel 48 | Routing messages: to add/del ip addresses for an interface 49 | 50 | ------------------------------------------------------------------- 51 | Trouble shot: 52 | 53 | Q. When i launch vrrpd, it display 'cant open raw socket', why ? 54 | A. try running it as root. 55 | vrrpd does several operations (set ip address, MAC address, send/rcv 56 | packet directly from the link) which require root access. 57 | 58 | Q. Why i can't have more than one virtual router per physical interface ? 59 | A. you can with the -n option which prevents vrrpd to handle the virtual MAC. 60 | It isnt compliant to the rfc but work in practice. 61 | VRRP requires to use a special MAC address for the ip packets with 62 | the address of the virtual router. Currently, as far as i know, 63 | linux doesnt support several MAC on transmition. so a host can't 64 | be MASTER of several group at the same time. 65 | It is possible to workaround this limitation by connecting several 66 | physical interfaces to the same link. 67 | 68 | Q. vrrpd doesn't set the virtual router addresses when it become master, why ? 69 | A. It is likely a problem when it try to set several addresses to 70 | the interface. the kernel must support ip aliasing. 71 | (linux configuration: Networking Option: IP aliasing support). 72 | 73 | Q. why it doesn't work with the implementation made by XXXX ? 74 | A. currently i have tested any inter-operability because i dont have 75 | any other implementations available. 76 | i did some intra-operabilty tests and it seems to work. 77 | 78 | ------------------------------------------------------------------- 79 | Technical: 80 | 81 | Q. What are the supported OS ? 82 | A. currently only linux. it is my development platform and don't have 83 | others available. 84 | 85 | Q. How hard would it be to port it on another OS ? 86 | A. i don't know. i use several 'low level' features which may be different 87 | or unavailable on other OS. a list follow: 88 | SIOCGIFADDR/SIOCSIFADDR to set/get the 'primary' hardware address 89 | SIOCADDMULTI/SIOCDELMULTI to add/remove a 'receiving' hardware address 90 | Use netlink to change the ip address, a clean but non standard way. 91 | 92 | Q. why vrrp packets are build by hand from vrrp payload to ethernet header ? 93 | A. the vrrp packets are send directly over the link without using a 94 | SOCK_RAW/IP_HDRINCL because of a requirement in the rfc2338.7.2 95 | "Set the source MAC address to the Virtual Router MAC Address" 96 | 97 | Q. how the MAC address change is handled ? 98 | A. I set the interface MAC address to the vrrp one. 99 | I set the original MAC address as a receiving MAC (multicast). 100 | thus i can send/receive packet with vrrp MAC and still receive 101 | packet with the old MAC. This avoid a system disruption at 102 | each change. nevertheless it prevent the user from running several 103 | virtual routers on a single physical interface. 104 | 105 | Q. how the IP address change is handled ? 106 | A. The virtual router addresses are set/removed as ip aliases. the 107 | primary ip address of the interface is never modified. 108 | Thus the connections using the primary ip (tcp or other) go on 109 | without trouble. 110 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | 1. uncompress the source 2 | 2. cd in the directory 3 | 3. type 'make clean' and 'make' 4 | 4. if everything is ok, there is now a file 'vrrpd' and 'atropos' in the directory 5 | 5. copy vrrpd iand atropos in your path (e.g /usr/sbin) and vrrpd.8 in your man path 6 | (e.g. /usr/man/man8) 7 | 8 | it requires to be run as root. 9 | 10 | ABOUT ARM 11 | 12 | In Makefile change: 13 | 14 | -CC = gcc 15 | 16 | By 17 | 18 | +CC = arm-v5te-linux-gnueabi-gcc 19 | 20 | 21 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PROJECT=vrrpd 2 | 3 | ALL_EXE=vrrpd atropos 4 | 5 | ATROPOS_OBJS = atropos.o 6 | 7 | VRRPD_OBJS = vrrpd.o libnetlink.o ipaddr.o 8 | 9 | MAIN_OPT= 10 | PROF_OPT= 11 | DBG_OPT=-g 12 | #MACHINEOPT=-DMY_BIG_ENDIAN -DSUNOS 13 | #MACHINEOPT=-DMY_LITTLE_ENDIAN 14 | #INCLUDEOPT= 15 | #INCLUDEOPT= -I./libpcap 16 | #LINKLIB = -lpcap 17 | COMMON_CFLAGS= $(MAIN_OPT) $(INCLUDEOPT) $(PROF_OPT) $(DBG_OPT) $(MACHINEOPT) 18 | 19 | # set to compile with GCC 20 | CC=gcc 21 | CFLAGS= $(COMMON_CFLAGS) -Wall 22 | 23 | all: $(ALL_EXE) 24 | 25 | vrrpd : $(VRRPD_OBJS) 26 | $(CC) $(PROF_OPT) -o $@ $^ -lrt $(LINKLIB) 27 | 28 | atropos:$(ATROPOS_OBJS) 29 | $(CC) $(PROF_OPT) -o $@ $^ -lrt 30 | 31 | vrrpd.o: vrrpd.h 32 | libnetlink.o: libnetlink.h 33 | 34 | dist: 35 | (make clean; rm -fr .protect/; cd ..; tar cvzf vrrpd-lastest.tgz vrrpd atropos) 36 | 37 | ############################################## 38 | # beyond this points only mangement target. # 39 | ############################################## 40 | clean : 41 | @echo Begin to clean 42 | $(RM) *.[ao] *~ core 43 | $(RM) $(ALL_EXE) 44 | @echo Clean is completed 45 | 46 | mrproper : clean 47 | @echo Begin to mrproper 48 | $(RM) -fr .depend .protect/ $(ALL_EXE) 49 | @echo Mrproper is completed 50 | 51 | strip : 52 | @echo Begin to strip $(ALL_EXE) 53 | $(STRIP) $(ALL_EXE) 54 | @echo $(ALL_EXE) have been striped 55 | 56 | backup: mrproper cleanlog 57 | @echo Backup to backup 58 | (cd .. && tar cf - $(PROJECT) | gzip -9 >$(PROJECT).tgz) 59 | sync 60 | @echo Backup is completed 61 | 62 | # only GCC. 63 | #depend dep: 64 | # @echo Start to build depedances in .depend 65 | # for i in *.c; do $(CPP) -M $(CFLAGS) $$i; done > .tmpdepend 66 | # mv -f .tmpdepend .depend 67 | # @echo Dependances completed 68 | 69 | # only gmake and good make 70 | #ifeq (.depend,$(wildcard .depend)) 71 | #include .depend 72 | #endif 73 | 74 | 75 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **Project moved to https://gitlab.com/fredbcode/Vrrpd** 2 | 3 | ## Advanced Vrrpd 4 | 5 | Advanced Vrrpd: high-availability solution, easy to use and easy to configure. 6 | No dependency is required, it works with very low memory and CPU usage. 7 | 8 | **A lightweight, fast, and free solution** 9 | 10 | That version has many improvements like monitoring other vrrpd processes and executing a command when changing back and forth from master to backup. 11 | 12 | You can also use atropos program for view or change global state. 13 | Tested on Linux only http://numsys.eu 14 | 15 | * VRRPD - when an interface change his state to backup, or master, them can have associated up/down scripts 16 | * VRRPD - Ethtool supervision (link up/down) 17 | * VRRPD - multi-interfaces - The Master communicate his state to all another process. If for some reason one process be backup, link down for example, all the system change for backup state. 18 | * VRRPD - Magic packet - If you can't use virtual mac adress, Vrrpd send gratuitous ARP and it can also send magic packet from virtual to gateway 19 | * VRRPD - Is now Compatible with vlan interfaces - with one vmac by vlan - 20 | * VRRPD - Optional subnet mask for the VIP address 21 | * Atropos client - You can use atropos for change or/and know the master's state (for example in supervision script) 22 | 23 | With vmac disable Spanning Tree Protocol (STP) on the switch ports where VRRP is running ! 24 | On VM vmac should be disabled (default: -n for enabled) 25 | 26 | The Virtual Router Redundancy Protocol (VRRP) is a computer networking protocol that provides for automatic assignment of available Internet Protocol (IP). 27 | 28 | Basic configuration: 29 | 30 | Server 1: 31 | 32 | vrrpd -i eth0 10.16.1.200 -v 51 -M 2 -U /etc/scripts/MASTER.sh -D /etc/scripts/DOWN.sh 33 | 34 | vrrpd -i eth1 10.17.1.200 -v 52 -M 2 -U /etc/scripts/MASTER.sh -D /etc/scripts/DOWN.sh 35 | 36 | Server 2: 37 | 38 | vrrpd -i eth0 10.16.1.200 -v 51 -M 2 -U /etc/scripts/MASTER.sh -D /etc/scripts/DOWN.sh 39 | 40 | vrrpd -i eth1 10.17.1.200 -v 52 -M 2 -U /etc/scripts/MASTER.sh -D /etc/scripts/DOWN.sh 41 | 42 | For init script you can take a look at: [github](https://github.com/fredbcode/Vrrpd/tree/master/configs) 43 | 44 | * i = eth to listen and VIP network adress (could vlan be VLAN like eth0.190) - 10.16.1.200 is the VIP shared on eth0 - 45 | * v = VID 51 46 | * M = M 2 monitoring two process on each machine (9 max), and eth link up/down supervision 47 | * U = Optional script when VRRPD become master 48 | * D = Optional script when VRRPD become backup 49 | 50 | **About U and D :** eg, you can configure some IP alias (or vlan) addresses who will share the VMAC (in this case don't forget to shutdown this adresses in backup script ...) 51 | 52 | In MASTER.sh 53 | 54 | ifconfig eth0:0 192.168.14.2 netmask 255.255.255.0 up 55 | 56 | In DOWN.sh 57 | 58 | ifconfig eth0:0 down 59 | 60 | Of course, you can put whatever you like. 61 | 62 | The virtual MAC address is automatically generated 63 | 64 | So, In our case there are three adresses on Master 65 | 66 | 10.17.1.200 and 192.168.14.2 on eth0 -> With same VMAC 67 | 68 | 10.17.1.20 on eth1 -> VMAC 69 | 70 | When one NIC is BACKUP, vrrpd process detect a failure and share with the 'other' network interface his own VRRP state. 71 | This prevent newtork problem because single interface failure can cause asymmetrical routing issues 72 | 73 | **vrrpd usage :** 74 | ``` 75 | vrrpd version Advanced Vrrpd 1.11 76 | Usage: vrrpd -i ifname -v vrid [ -M monitor ] [-s] [-a auth] [-p prio] [-z prio] [-x prio] [-nh] ipaddr 77 | -h : display this short inlined help 78 | -n : handle the virtual mac address 79 | -i ifname: the interface name to run on 80 | -v vrid : the id of the virtual server [1-255] 81 | -s : Switch the preemption mode (Enabled by default) 82 | -a auth : auth=(none|pw/hexkey|ah/hexkey) hexkey=0x[0-9a-fA-F]+ 83 | -p prio : Set the priority of this host in the virtual server (dfl: 100) 84 | -d delay : Set the advertisement interval (in sec) (dfl: 1) 85 | -z prio : Set the priority after SIGTTIN (not decrement as default) 86 | -x prio : Set the priority after SIGTTOU (not increment as default) 87 | ipaddr/length : Should be at the end - IP address(es) of the virtual server and the length of the subnet mask - 88 | -V : display version 89 | 90 | --------------------------------------------------------------------------- 91 | Frederic Bourgeois http://numsys.eu 92 | https://github.com/fredbcode/ 93 | Based on (http://sourceforge.net/projects/vrrpd/) 94 | 95 | Supplementary Options: 96 | -U : (-U ): run to become a master) 97 | -D : (-D ): run to become a backup) 98 | -M : (-M x) Monitoring process and Network (Max 9) 99 | If one vrrpd become backup (or died), all other process go to Backup state 100 | If one network interface failed (ifconfig Down, link) all other process go to Backup state 101 | Not supported (in part or whole) on all ethernet drivers 102 | POWER USERS -------------------------------------------------------------- 103 | Magic packet erase arp table (for those who work without vmac - send fake packet to port 1100 -) 104 | -I ipvip : Choose VIP source to send magic packet - Erase vip from mac table - 105 | -O ipdst : Gateway destination 106 | Example vrrpd -I 10.1.1.1 -O 10.1.1.254 107 | ``` 108 | **Atropos usage:** 109 | ``` 110 | Atropos 0.70 frederic Bourgeois http://numsys.eu 111 | 112 | atropos --backup Be backup (caution: Don't use with priority !) 113 | atropos --reduce Reduce priority dynamically priority -10 114 | If vrrpd run with -z : Set the priority after SIGTTIN (not decrement as default) 115 | atropos --increase Increase priority dynamically +10 116 | If vrrpd run with -x : Set the priority after SIGTTOU (not increment as default) 117 | atropos --help This Page 118 | atropos --state Status 119 | atropos --version version 120 | It requires to be run as root 121 | ``` 122 | 123 | With atropos --state 124 | 125 | syslog file contains detailed information about VRRPD state 126 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | Feature: 2 | - launch a script according to the state change. 3 | - add a test to set automatically the priority to 255 when the host 4 | own the ip addresses 5 | - as vrrpd needs root access, audit the code security. 6 | - test interoperability. 7 | - code the plain text authentication and hardcode AH. 8 | - make the master down interval tunable. 9 | - work only with ethernet, all is hardcoded. it is ugly. 10 | see what you can do for fddi/tokenring -> problem i dont have the hardware 11 | so i can't test. 12 | - beautifull the code. 13 | 14 | 15 | - change the state according to unix signal USR1=be master, USR2=be backup 16 | pid stored in a file vrrpd_[IF]_[VRID].pid (e.g. vrrp_eth0_50.pid) DONE 17 | - provide a mode in which you don't change the MAC address and thus support 18 | multiple virtual router per physical interface. DONE (-n) 19 | 20 | 21 | Things to test: 22 | - vrrpd vs commercial version 23 | - vrrpd vs vrrpd 24 | - multiple authentications (NONE,passwd, AH) 25 | - checksum 26 | 27 | -------------------------------------------------------------------------------- /atropos.c: -------------------------------------------------------------------------------- 1 | /* Mode: C; 2 | * Atropos frederic Bourgeois https://gitlab.com/fredbcode 3 | */ 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | #include 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 | /* local include */ 23 | #include "vrrpd.h" 24 | 25 | #ifdef use_linux_libc5 26 | #endif 27 | 28 | typedef u_int32_t u32; 29 | typedef u_int16_t u16; 30 | typedef u_int8_t u8; 31 | 32 | #if defined(SIOCGPARAMS) && SIOCGPARAMS != SIOCDEVPRIVATE+3 33 | #error Changed definition for SIOCGPARAMS 34 | #else 35 | #define SIOCGPARAMS (SIOCDEVPRIVATE+3) /* Read operational parameters. */ 36 | #define SIOCSPARAMS (SIOCDEVPRIVATE+4) /* Set operational parameters. */ 37 | #endif 38 | #define DATA_MAX 10000 39 | 40 | int max_monitor = 9; 41 | char version1[10] = "1.0"; 42 | char buff[80]; 43 | char data[DATA_MAX]; 44 | char pidend[6] = ".pid"; 45 | char separetepath[2] = "/"; 46 | int monitor; 47 | int pid; 48 | int ix = 0; 49 | int max_mac = 6; 50 | // Five loop with twice SIGNAL 51 | int max_count = 5; 52 | int nb; 53 | int retval; 54 | 55 | static char PidDir[FILENAME_MAX+1]; 56 | char namepid[FILENAME_MAX+1]="vrrpd_"; 57 | char temp[FILENAME_MAX+1]; 58 | char finalfile[FILENAME_MAX+1]; 59 | 60 | DIR *currentDir; 61 | struct dirent *fichier; 62 | 63 | const char shortopts[] = "aA:bB:fF:Mn:sS:hH:p:rRsvVw?"; 64 | 65 | struct option longopts[] = { 66 | /* { name has_arg *flag val } */ 67 | {"state", 0, 0, 's'}, 68 | {"help", 0, 0, 'h'}, 69 | {"backup", 0, 0, 'b'}, 70 | {"reduce", 0, 0, 'r'}, 71 | {"increase", 0, 0, 'i'}, 72 | {"master", 0, 0, 'm'}, 73 | {"version", 0, 0, 'v'}, 74 | {"error", 0, 0, '?'}, 75 | { 0, 0, 0, 0 } 76 | }; 77 | 78 | char ligne[80]; 79 | int cpt = 0; 80 | char buf[80]; 81 | int s, i; 82 | FILE * filestate; 83 | FILE *f; 84 | 85 | unsigned int opt_a = 0, /* Show-all-interfaces flag. */ /* Verbose flag. */ 86 | state = 0, 87 | version = 0, 88 | backup = 0, 89 | master = 0, 90 | increase = 0, 91 | reduce = 0; 92 | 93 | void fonctinfo() { 94 | 95 | FILE * child_process = popen("ps -e |grep vrrpd | wc -l", "r"); 96 | fgets(buf, sizeof(buf), child_process); 97 | pclose(child_process); 98 | printf("############################################################\n\n"); 99 | if (child_process == NULL) 100 | fprintf(stdout,"Could not open pipe:\n"); 101 | if ( !strncmp(buf, "0", 1 )) { 102 | fprintf(stdout, "\n"); 103 | fprintf(stdout,"VRRPD RUN: 0\n"); 104 | exit(0); 105 | } 106 | snprintf( PidDir, sizeof(PidDir), "%s", VRRP_PIDDIR_DFL ); 107 | 108 | if( NULL == ( currentDir = opendir(PidDir))) { 109 | perror( "opendir()" ); 110 | } else { 111 | while( NULL != ( fichier = readdir( currentDir ))) { 112 | if(!strncmp(namepid, fichier->d_name, 6) ){ 113 | strcpy(finalfile,PidDir); 114 | strcat(finalfile,separetepath); 115 | strcat(finalfile,fichier->d_name); 116 | if ((f = fopen(finalfile, "rb")) != NULL){ 117 | fgets(buff, sizeof(buff), f); 118 | fclose(f); 119 | int pid = atoi(buff); 120 | kill(pid,SIGUSR1); 121 | char vrrp_tmp[FILENAME_MAX] = VRRP_PIDDIR_DFL; 122 | sleep(1); 123 | snprintf(temp, sizeof(temp), "/.vrrpstate%d", pid); 124 | strcat(vrrp_tmp, temp); 125 | if ((f = fopen(vrrp_tmp, "r")) != NULL){ 126 | while (fgets(data, DATA_MAX, f) != NULL) 127 | { 128 | printf("%s", data); 129 | } 130 | } else { 131 | fprintf(stdout, "VRRP PID %d File %s STATE NOT FOUND \n", pid, vrrp_tmp); 132 | } 133 | } 134 | finalfile[0]='\0'; 135 | printf("\n"); 136 | printf("############################################################\n\n"); 137 | } 138 | } 139 | } 140 | 141 | // End Loop // 142 | FILE *filestate = popen("ps -fC vrrpd", "r"); 143 | if (filestate != NULL){ 144 | while (fgets (ligne, sizeof ligne, filestate) != NULL){ 145 | cpt++; 146 | printf ("%s",ligne); 147 | } 148 | fclose (filestate); 149 | } else { 150 | printf ("Erreur d'ouverture du fichier\n"); 151 | } 152 | 153 | 154 | printf("\n"); 155 | for (ix=0; ix < max_mac; ix++) { 156 | struct ifreq devea; 157 | int ether = ix; 158 | s = socket(AF_INET, SOCK_DGRAM, 0); 159 | if (s < 0) 160 | { 161 | perror("socket"); 162 | exit(1); 163 | } 164 | 165 | sprintf(devea.ifr_name, "eth%d", ether); 166 | if (ioctl(s, SIOCGIFHWADDR, &devea) == 0) 167 | { 168 | printf("eth%d Current MAC is: ",ether); 169 | for (i = 0; i < max_mac; i++) 170 | { 171 | if (i < (max_mac - 1)) 172 | printf("%2.2x:", i[devea.ifr_hwaddr.sa_data] & 0xff); 173 | if (i == (max_mac - 1)) 174 | printf("%2.2x", i[devea.ifr_hwaddr.sa_data] & 0xff); 175 | } 176 | printf("\n"); 177 | } 178 | } 179 | printf("\n"); 180 | char command[FILENAME_MAX+50]; 181 | snprintf(command,sizeof command,"grep -sh state %s/.*vrrpstate*",PidDir); 182 | system(command); 183 | 184 | snprintf(command,sizeof command,"rm %s/.*vrrpstate*",PidDir); 185 | system(command); 186 | 187 | printf("\n"); 188 | fprintf(stdout, "Be careful, Atropos doesn't show virtual mac address of vlan interface"); 189 | printf("\n"); 190 | fprintf(stdout, "Take a look at syslog for more informations"); 191 | printf("\n"); 192 | } 193 | 194 | static void signal_end( int nosig ) 195 | { 196 | fprintf(stdout,"\n"); 197 | signal( SIGINT, signal_end ); 198 | return; 199 | } 200 | 201 | 202 | int main(int argc, char **argv) 203 | { 204 | signal( SIGINT, signal_end ); 205 | int c, errflag = 0; 206 | while ((c = getopt_long(argc, argv, shortopts, longopts, 0)) != EOF) 207 | switch (c) { 208 | case 's': state++; break; 209 | case 'v': version++; break; 210 | case 'b': backup++; break; 211 | case 'r': reduce++; break; 212 | case 'i': increase++; break; 213 | case 'm': master++; break; 214 | case '?': errflag++; break; 215 | } 216 | 217 | if (state) { 218 | fonctinfo(); 219 | return 0; 220 | }; 221 | 222 | if (version) { 223 | fprintf(stdout,"Atropos %s\n", version1); 224 | return 0; 225 | }; 226 | 227 | 228 | if (reduce) { 229 | snprintf( PidDir, sizeof(PidDir), "%s", VRRP_PIDDIR_DFL ); 230 | fprintf(stdout,"Please wait\n"); 231 | 232 | sleep (1); 233 | if( NULL == ( currentDir = opendir(PidDir))) { 234 | perror( "opendir()" ); 235 | } else { 236 | while( NULL != ( fichier = readdir( currentDir ))) { 237 | if(!strncmp(namepid, fichier->d_name, 6) ){ 238 | strcpy(finalfile,PidDir); 239 | strcat(finalfile,separetepath); 240 | strcat(finalfile,fichier->d_name); 241 | if ((f = fopen(finalfile, "rb")) != NULL){ 242 | fgets(buff, sizeof(buff), f); 243 | fclose(f); 244 | int pid = atoi(buff); 245 | kill(pid,SIGTTIN); 246 | finalfile[0]='\0'; 247 | } 248 | } 249 | } 250 | } 251 | 252 | fprintf(stdout,"DONE\n"); 253 | return 0; 254 | }; 255 | 256 | if (increase) { 257 | snprintf( PidDir, sizeof(PidDir), "%s", VRRP_PIDDIR_DFL ); 258 | fprintf(stdout,"Please wait\n"); 259 | 260 | sleep (1); 261 | if( NULL == ( currentDir = opendir(PidDir))) { 262 | perror( "opendir()" ); 263 | } else { 264 | while( NULL != ( fichier = readdir( currentDir ))) { 265 | if(!strncmp(namepid, fichier->d_name, 6) ){ 266 | strcpy(finalfile,PidDir); 267 | strcat(finalfile,separetepath); 268 | strcat(finalfile,fichier->d_name); 269 | if ((f = fopen(finalfile, "rb")) != NULL){ 270 | fgets(buff, sizeof(buff), f); 271 | fclose(f); 272 | int pid = atoi(buff); 273 | kill(pid,SIGTTOU); 274 | finalfile[0]='\0'; 275 | } 276 | } 277 | } 278 | } 279 | 280 | fprintf(stdout,"DONE\n"); 281 | return 0; 282 | }; 283 | 284 | 285 | if (backup) { 286 | snprintf( PidDir, sizeof(PidDir), "%s", VRRP_PIDDIR_DFL ); 287 | fprintf(stdout,"VRRPD BACKUP\n"); 288 | fprintf(stdout,"PLEASE WAIT\n"); 289 | for (ix = 0; ix <= max_count; ix++) { 290 | fprintf(stderr, "\n"); 291 | fprintf(stderr,"Stage: %d|%d: ", ix, max_count); 292 | sleep (1); 293 | fprintf(stderr,"\b"); 294 | fprintf(stderr,"|"); 295 | if( NULL == ( currentDir = opendir(PidDir))) { 296 | perror( "opendir()" ); 297 | } else { 298 | while( NULL != ( fichier = readdir( currentDir ))) { 299 | if(!strncmp(namepid, fichier->d_name, 6) ){ 300 | strcpy(finalfile,PidDir); 301 | strcat(finalfile,separetepath); 302 | strcat(finalfile,fichier->d_name); 303 | if ((f = fopen(finalfile, "rb")) != NULL){ 304 | fgets(buff, sizeof(buff), f); 305 | fclose(f); 306 | int pid = atoi(buff); 307 | kill(pid,SIGUSR2); 308 | finalfile[0]='\0'; 309 | } 310 | } 311 | } 312 | } 313 | sleep(1); 314 | fprintf(stderr,"\b"); 315 | fprintf(stderr,"/"); 316 | sleep (1); 317 | fprintf(stderr,"\b"); 318 | fprintf(stderr,"-"); 319 | sleep (1); 320 | fprintf(stderr,"\b"); 321 | fprintf(stderr,"DONE"); 322 | if( NULL == ( currentDir = opendir(PidDir))) { 323 | perror( "opendir()" ); 324 | } else { 325 | while( NULL != ( fichier = readdir( currentDir ))) { 326 | if(!strncmp(namepid, fichier->d_name, 6) ){ 327 | strcpy(finalfile,PidDir); 328 | strcat(finalfile,separetepath); 329 | strcat(finalfile,fichier->d_name); 330 | if ((f = fopen(finalfile, "rb")) != NULL){ 331 | fgets(buff, sizeof(buff), f); 332 | fclose(f); 333 | int pid = atoi(buff); 334 | kill(pid,SIGUSR2); 335 | finalfile[0]='\0'; 336 | } 337 | } 338 | } 339 | } 340 | 341 | } 342 | 343 | fprintf(stdout,"\n"); 344 | fprintf(stdout,"OK \n"); 345 | fonctinfo(); 346 | return 0; 347 | } 348 | 349 | else { 350 | fprintf(stdout,"\n"); 351 | fprintf(stdout,"Atropos %s frederic Bourgeois https://gitlab.com/fredbcode\n", version1); 352 | fprintf(stdout,"\n"); 353 | fprintf(stdout,"atropos --backup Be backup (caution: Do not use with priority !)\n"); 354 | fprintf(stdout,"atropos --reduce Reduce priority dynamically priority -10\n"); 355 | fprintf(stdout," If vrrpd run with -z : Set the priority after SIGTTIN (not decrement as default)\n"); 356 | fprintf(stdout,"atropos --increase Increase priority dynamically +10 \n"); 357 | fprintf(stdout," If vrrpd run with -x : Set the priority after SIGTTOU (not increment as default)\n"); 358 | fprintf(stdout,"atropos --help This Page\n"); 359 | fprintf(stdout,"atropos --state Status \n"); 360 | fprintf(stdout,"atropos --version version \n"); 361 | fprintf(stdout,"It requires to be run as root \n"); 362 | return 0; 363 | } 364 | 365 | } 366 | -------------------------------------------------------------------------------- /configs/vrrp: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | ### BEGIN INIT INFO 3 | # Provides: vrrp 4 | # Required-Start: $remote_fs $syslog 5 | # Required-Stop: $remote_fs $syslog 6 | # Default-Start: 2 3 4 5 7 | # Default-Stop: 0 1 6 8 | # Short-Description: vrrp 9 | # Description: HA 10 | ### END INIT INFO 11 | . /lib/lsb/init-functions 12 | 13 | PATH=/bin:/usr/bin:/sbin:/usr/sbin 14 | 15 | pidvrrpd=`pidof -x vrrpd` 16 | horodate=$(date +%d/%m/%Y_%r) 17 | conf=/etc/vrrp.conf 18 | 19 | if [ ! -f $conf ]; then 20 | log_daemon_msg "No configuration file" 21 | RET="$?" 22 | log_end_msg $RET 23 | exit 0 24 | fi 25 | 26 | start() { 27 | log_daemon_msg "." 28 | pidof -x vrrpd > /dev/null 29 | if [ $? = 1 ]; then 30 | log_daemon_msg "Start vrrpd .." 31 | $conf > /dev/null 32 | log_daemon_msg "Start: done" 33 | else 34 | log_daemon_msg "vrrpd was already started ..." 35 | log_daemon_msg "vrrp pid: $pidvrrpd" 36 | fi 37 | RET="$?" 38 | log_end_msg $RET 39 | } 40 | 41 | stop() { 42 | log_daemon_msg "." 43 | pidof -x vrrpd > /dev/null 44 | if [ $? = 0 ]; then 45 | log_action_begin_msg "Stop vrrpd .." 46 | cnt=0 47 | killall vrrpd 48 | log_action_begin_msg "Exit Vrrpd: State backup and Shutting down PID: " && pidof vrrpd 49 | while pidof vrrpd >/dev/null 50 | do 51 | cnt=`expr $cnt + 1` 52 | if [ $cnt -gt 60 ] 53 | then 54 | log_daemon_msg "Can't stop vrrpd ?" 55 | RET="$?" 56 | log_end_msg $RET 57 | exit 0 58 | fi 59 | sleep 1 60 | log_action_begin_msg "Please Wait" "$cnt : Pid en cours de fonctionnement " && pidof vrrpd 61 | done 62 | log_daemon_msg "stop: done" 63 | else 64 | log_daemon_msg "vrrpd was already stopped" 65 | fi 66 | RET="$?" 67 | log_end_msg $RET 68 | } 69 | 70 | case "$1" in 71 | start) 72 | start 73 | ;; 74 | stop) 75 | stop 76 | ;; 77 | 78 | restart|reload) 79 | stop 80 | start 81 | ;; 82 | *) 83 | log_daemon_msg "Usage: /etc/init.d/vrrp {start|stop|restart}" >&2 84 | RET="$?" 85 | log_end_msg $RET 86 | exit 1 87 | ;; 88 | esac 89 | exit 0 90 | 91 | -------------------------------------------------------------------------------- /configs/vrrp.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=vrrpd 3 | After=network.target auditd.service 4 | 5 | [Service] 6 | Type=forking 7 | Restart=no 8 | TimeoutSec=5min 9 | IgnoreSIGPIPE=no 10 | KillMode=process 11 | GuessMainPID=no 12 | RemainAfterExit=yes 13 | SysVStartPriority=20 14 | ExecStart=/etc/vrrpd/startup.sh start 15 | ExecStop=/etc/vrrpd/startup.sh stop 16 | 17 | [Install] 18 | WantedBy=multi-user.target 19 | Alias=vrrp.service 20 | -------------------------------------------------------------------------------- /configs/vrrpd/Backup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # When vrrpd become Backup 3 | 4 | #------------------------------- 5 | PATH=/sbin:/bin:/usr/sbin:/usr/bin 6 | #variables 7 | horodate=$(date +%d/%m/%Y_%R) 8 | month=$(date +%b) 9 | ##--------------------------------## 10 | 11 | echo "Down int" 12 | ifconfig eth1:0 down 13 | 14 | # IF NEEDEED (no virtual MAC) 15 | # REFRESH MAC 16 | # ping -c 2 -I YOURADRESS GATEWAY 17 | 18 | exit 0 19 | -------------------------------------------------------------------------------- /configs/vrrpd/Master.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # When vrrpd become Master 3 | # 4 | #------------------------------- 5 | # THIS IS A SAMPLE FILE WITH ONE IP ALIAS 6 | # ADAPT TO YOUR OWN CONFIGURATION ! 7 | 8 | PATH=/sbin:/bin:/usr/sbin:/usr/bin 9 | horodate=$(date +%d/%m/%Y_%R) 10 | ##--------------------------------## 11 | 12 | echo "1" > /proc/sys/net/ipv4/ip_forward 13 | 14 | echo "Montage int" 15 | # DON'T FORGET ! MUST BE REMOVED IN backup.sh 16 | ifconfig eth1:0 192.168.14.2 netmask 255.255.255.0 up 17 | # IF NEEDEED 18 | # REFRESH MAC 19 | # ping -c 2 -I 192.168.14.2 192.168.14.254 (GATEWAY) 20 | 21 | echo "ROUTE" 22 | /etc/init.d/route.sh 23 | 24 | exit 0 25 | -------------------------------------------------------------------------------- /configs/vrrpd/startup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin 3 | # 4 | # Date:11 Sept 2006 yh ps 5 | # Nom:vrrp_on.sh 6 | # 7 | # Sample 8 | # 9 | #--------------------------------- 10 | # Please take a look -> vrrpd client: atropos --help 11 | # THIS IS A SAMPLE FILE WITH TWO PROCESS (TWO NICS) 12 | # ADAPT TO YOUR OWN CONFIGURATION ! 13 | 14 | horodate=$(date +%d/%m/%Y_%R) 15 | 16 | # Parameters 17 | # script - vrrp state change - 18 | 19 | if [ "$1" = "" ] 20 | then 21 | exit 1 22 | fi 23 | 24 | if [ "$1" = 'stop' ] 25 | then 26 | pidof vrrpd > /dev/null 27 | if [ "$?" = 1 ] 28 | then 29 | echo "Pid vrrpd already stopped" 30 | exit 0 31 | fi 32 | while pidof vrrpd 2>/dev/null 33 | do 34 | echo "Pid running" 35 | killall vrrpd 36 | sleep 5 37 | done 38 | exit 0 39 | fi 40 | if [ "$1" = 'start' ] 41 | then 42 | #-------------------------------- 43 | # MOUNT vrrpd 44 | echo "MOUNT vrrpd " 45 | # BY DEFAULT VIRTUAL MAC IS DISABLED (virtual mac = -n) 46 | # ACTIVATE AT YOUR OWN RICK 47 | # SPANNING TREE MUST BE DISABLED 48 | # IF MAC REFRESH IS TOO SLOW A PING FROM VIP TO THE GATEWAY CAN BE ALSO AN ALTERNATIVE (in master & backup script) 49 | # Vmac is technically efficient, but it's incompatible with some hardwares and virtual machines 50 | 51 | /etc/vrrpd/vrrp_on.sh 52 | 53 | # check if there is the same number of process than $ps 54 | ps=`grep ps= /etc/vrrp.conf |cut -d "=" -f2` 55 | checkproc=`pgrep vrrpd | wc -w` 56 | if [ "$checkproc" -ne "$ps" ] 57 | then 58 | echo "vrrp.conf: ps value must be equal at the number of process !" 59 | exit 1 60 | fi 61 | sleep 5 62 | fi 63 | -------------------------------------------------------------------------------- /configs/vrrpd/vrrp_on.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin 3 | # 4 | # Date:11 Sept 2006 yh ps 5 | # Nom:vrrp_on.sh 6 | # 7 | # Sample 8 | # 9 | #--------------------------------- 10 | # Please take a look -> vrrpd client: atropos --help 11 | # THIS IS A SAMPLE FILE WITH TWO PROCESS (TWO NICS) 12 | # ADAPT TO YOUR OWN CONFIGURATION ! 13 | 14 | horodate=$(date +%d/%m/%Y_%R) 15 | 16 | # Parameters 17 | # script - vrrp state change - 18 | up=/etc/vrrpd/Master.sh 19 | down=/etc/vrrpd/Backup.sh 20 | 21 | # number of process vrrp MUST be equal the process number 22 | ps=2 23 | 24 | #Vrrp,Vid,eg 2 vrrpd 25 | int0=eth0 26 | id0=11 27 | vrrip0=192.168.11.1 28 | 29 | int1=eth1 30 | id1=14 31 | vrrip1=192.168.14.1 32 | 33 | echo "MOUNT vrrpd " 34 | # BY DEFAULT VIRTUAL MAC IS DISABLED (virtual mac = -n) 35 | # ACTIVATE AT YOUR OWN RICK 36 | # SPANNING TREE MUST BE DISABLED 37 | # IF MAC REFRESH IS TOO SLOW A PING FROM VIP TO THE GATEWAY CAN BE ALSO AN ALTERNATIVE (in master & backup script) 38 | # Vmac is technically efficient, but it's incompatible with some hardwares and virtual machines 39 | 40 | # Directly related with $ps ! 41 | 42 | # Add or remove here your process the up script is only needed at first 43 | 44 | vrrpd -i $int0 -v $id0 -M $ps $vrrip0 -d 2 -U $up -D $down 45 | vrrpd -i $int1 -v $id1 -M $ps $vrrip1 -d 2 -D $down 46 | -------------------------------------------------------------------------------- /doc/draft-jou-duplicate-ip-address-02.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Network Working Group T.-S. Jou 7 | INTERNET-DRAFT IBM Corporation 8 | Updates: RFC 826 February, 1999 9 | 10 | 11 | Duplicate IP Address Detection Based on Gratuitous ARP 12 | 13 | 14 | Status of this Memo 15 | 16 | This document is an Internet-Draft and is in full conformance 17 | with all provisions of Section 10 of RFC2026. 18 | 19 | Internet-Drafts are working documents of the Internet Engineering 20 | Task Force (IETF), its areas, and its working groups. Note that 21 | other groups may also distribute working documents as 22 | Internet-Drafts. 23 | 24 | Internet-Drafts are draft documents valid for a maximum of six 25 | months and may be updated, replaced, or obsoleted by other 26 | documents at any time. It is inappropriate to use Internet- 27 | Drafts as reference material or to cite them other than as 28 | "work in progress." 29 | 30 | To view the list Internet-Draft Shadow Directories, see 31 | http://www.ietf.org/shadow.html. 32 | 33 | 34 | Copyright Notice 35 | 36 | Copyright (C) The Internet Society (1999). All Rights Reserved. 37 | 38 | 39 | Abstract 40 | 41 | The Address Resolution Protocol specifies the scheme to resolve the 42 | hardware address of a host by using its IP address. The hardware 43 | addresses are normally unique for each hardware module because they 44 | were assigned by manufacturers; but there is much less control on the 45 | uniqueness of IP addresses on a LAN. With the booming network 46 | popularity, the possibility of the same IP address being used on 47 | different hosts is increasing. The duplication may come from users' 48 | or network administrators' mistakes, or configuration errors on host 49 | addresses assigning programs such as BOOTP or DHCP servers. This 50 | document is to define an extension to the original ARP protocol to 51 | prevent a newly configured host from making much damage to a host 52 | that has been the owner of the same IP address. The solution is 53 | based on the de-facto gratuitous ARP packets with modification on a 54 | host's behavior when an address duplication is detected. 55 | 56 | 57 | 58 | Jou [Page 1] 59 | INTERNET_DRAFT Duplicate IP Address Detection February, 1999 60 | 61 | 62 | Acknowledgments 63 | 64 | This document was first prepared while the author was an IBM 65 | employee. The initial idea was confirmed and tested with help from 66 | Lori Napoli and Sajay Khanna in IBM. Thanks also go to Mike Patton 67 | in MAP Network Engineering, Inc., for pointing out the security 68 | concerns. 69 | 70 | 71 | 1. Introduction 72 | 73 | The Address Resolution Protocol, defined in RFC 826 [1], is used 74 | to determine a host's hardware address based on its network address. 75 | To adapt to the possible changes of the association between a 76 | hardware address and an IP address, two mechanisms are specified in 77 | the RFC: 78 | 79 | (1) When a host receives an ARP packet and the sender IP address 80 | exists in its ARP table, the host should update the cached 81 | ARP entry with the sender hardware address in the packet. 82 | (2) Each host ages away old ARP entries to allow changes on the 83 | network. 84 | 85 | There are increasing number of hosts that are connected to networks 86 | and have IP addresses assigned, some of them dynamically, hence there 87 | are increasing number of possibilities that the same IP address is 88 | assigned to multiple hosts on a LAN. RFC 826 oversees this problem. 89 | Later in this document we can see the above mechanisms even causes 90 | catastrophic problems. If address duplication ever occurs, 91 | neither of the two hosts sharing the same address can be reliably 92 | reached by others because the unpredictable hardware address 93 | resolution on the shared IP address. This is especially a serious 94 | threat to a server that many clients depend on. 95 | 96 | The problem can be avoided gracefully if following three conditions 97 | are achieved: 98 | 99 | (a) The host that attempts to use a duplicate IP address can detect 100 | this address is being used by another host, and stop using this 101 | address immediately, possibly via turning down its interface. 102 | (b) The host that originally owns the IP address notifies the 103 | the attempting host for the duplication, and then keep operating. 104 | (c) The confusion caused by the second host's attempt can be reduced 105 | to minimum for all other hosts on the network. 106 | 107 | A host running one of many latest TCP/IP implementations can generate 108 | a gratuitous ARP packet when any of its interfaces is configured, 109 | usually at booting time. The gratuitous ARP packet is an ARP request 110 | with both sender and the target IP address fields containing the 111 | configured IP address. This de-facto behavior can be deployed to 112 | detect IP address duplication. After seeing the gratuitous packets, a 113 | 114 | 115 | 116 | Jou [Page 2] 117 | INTERNET_DRAFT Duplicate IP Address Detection February, 1999 118 | 119 | 120 | host following RFC 826 will send an ARP reply if the address is being 121 | configured on one of its interfaces. Due to the lack of standards, 122 | once the gratuitous ARP sender receives the unexpected ARP reply, the 123 | response varies. Most implementations can display warning messages 124 | on their consoles or to create error logs. Some implementation allows 125 | both hosts to keep using this IP address until the problem is 126 | corrected manually. Some other implementations disable the networking 127 | capability on both hosts and require both hosts to be reconfigured 128 | and possibly be rebooted. The latter implementation makes the hosts 129 | very vulnerable to configuration errors. The correct behavior should 130 | be that the host originally owns this IP address keeps operating, 131 | while error messages are reported to draw network administrator's 132 | attention. The host that attempts to use a duplicate IP address 133 | should stop operating on this address. 134 | 135 | The problem cannot be fully solved without addressing Condition (c). 136 | Since a gratuitous ARP request is a link-layer broadcast packet, all 137 | hosts on the network will receive it. According to RFC 826, all hosts 138 | that have this IP address cached in their ARP tables will update the 139 | entry with the sender hardware address. This behavior originally is 140 | designed to allow a host that has just changed its hardware address 141 | (such as interface card is replaced) to be able to update others. 142 | However, this design results in these hosts not being able to reach 143 | the original IP address owner until their ARP entry expires, even if 144 | the gratuitous ARP sender stops using the address immediately. Since 145 | the gratuitous ARP packet just updated every host's ARP entry, the 146 | entry will be valid for the full ARP entry lifetime, normally 20 147 | minutes. 148 | 149 | As specified by RFC 826, the ARP reply from the original IP address 150 | owner is a unicast packet, hence the hosts with the ARP entry cached 151 | will not be aware of the occurrence of duplication. To correct the 152 | problem, this document specifies the reply of the gratuitous ARP to 153 | be a link-layer broadcast packet, hence Condition (c) can be achieved 154 | because all other hosts will be able to receive the ARP reply and 155 | change their cached entries back to destine to the original address 156 | owner. Even thought there is still a window of time that the cached 157 | entries are destined to the gratuitous ARP sender, the time period is 158 | much shorter than the ARP entry lifetime. 159 | 160 | 161 | 2. Discussion of an Alternative to Broadcast Reply 162 | 163 | An alternative to replying with a broadcast ARP reply packet is to 164 | let the original address owner to send a gratuitous ARP packet again, 165 | which can correct other hosts' cached entries as well. However, if 166 | for whatever reason the host attempting to use the duplicate IP 167 | address chooses to continue operating, that host will reply with an 168 | ARP packet. Once the original address owner receives the reply, it 169 | becomes a protocol dilemma whether to send another gratuitous ARP, 170 | which potentially can cause an infinite looping of ARP packets 171 | between the two hosts, or, to hand over the IP address to the new 172 | host, which violates Condition (b) we would like to achieve. 173 | 174 | Jou [Page 3] 175 | INTERNET_DRAFT Duplicate IP Address Detection February, 1999 176 | 177 | 178 | On the other hand, if the link-layer broadcast ARP reply is sent by 179 | the original address owner but for some reason the host attempting to 180 | use the duplicate IP address is still operating, those hosts that 181 | have the ARP entry cached will be able to keep communicating with the 182 | original address owner until their ARP entries expire. Since these 183 | entries are updated by the broadcast reply, they will remain valid 184 | for approximately the full entry lifetime. But those hosts that have 185 | to resolve this IP address will see undetermined results. However, if 186 | the duplication problem can be fixed in time, perhaps manually by the 187 | users or the network administrator, the proposed scheme still causes 188 | lesser damage to all hosts on the network. 189 | 190 | 191 | 3. The Solution 192 | 193 | The implementation details of the solution is described in this 194 | section. The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", 195 | "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and 196 | "OPTIONAL" in this document are to be interpreted as described in 197 | RFC 2119. 198 | 199 | (1) A gratuitous ARP request packet MUST be generated in two 200 | situations: 201 | (i) when an IP address is being assigned to a working interface, 202 | and 203 | (ii) when an interface that has IP address assigned is being 204 | turned up from down. 205 | 206 | A gratuitous ARP packet on an Ethernet is defined as 207 | 208 | 48.bit Destination Address = 0xffffffffffff (broadcast) 209 | 48.bit Source Address = Hardware address of interface 210 | 16.bit Frame type = 0x806 (ARP) 211 | ---------------------- 212 | 16.bit Hardware type = 0x1 (Ethernet) 213 | 16.bit Protocol Type = 0x800 (IP) 214 | 8.bit Hardware Address size = 6 215 | 8.bit Protocol Address size = 4 216 | 16.bit Opcode = 1 (Request) 217 | 48.bit Sender Ethernet Address = Hardware address of interface 218 | 32.bit Sender IP Address = Configured IP address 219 | 48.bit Target Ethernet Address = Don't care 220 | 32.bit Target IP Address = Configured IP Address 221 | 222 | 223 | (2) If a host receives an ARP request packet in which the target IP 224 | address and the sender IP address fields are the same and it 225 | matches the address of the receiving interface, it implies 226 | IP address duplication happens. The host MUST send a link-layer 227 | broadcast ARP reply as defined below. The host SHOULD report, 228 | log, and/or display warning messages to indicate the detection of 229 | IP address duplication. 230 | 231 | 232 | Jou [Page 4] 233 | INTERNET_DRAFT Duplicate IP Address Detection February, 1999 234 | 235 | 236 | 48.bit Destination Address = 0xffffffffffff (broadcast) 237 | 48.bit Source Address = Hardware address of interface 238 | 16.bit Frame type = 0x806 (ARP) 239 | ---------------------- 240 | 16.bit Hardware type = 0x1 (Ethernet) 241 | 16.bit Protocol Type = 0x800 (IP) 242 | 8.bit Hardware Address size = 6 243 | 8.bit Protocol Address size = 4 244 | 16.bit Opcode = 2 (Reply) 245 | 48.bit Sender Ethernet Address = Hardware address of interface 246 | 32.bit Sender IP Address = Local IP address 247 | 48.bit Target Ethernet Address = Sender Addr in Request packet 248 | 32.bit Target IP Address = Local IP Address 249 | 250 | (3) Within a small time period after a host sends a gratuitous ARP 251 | packet, if the host receives an ARP reply with both sender IP 252 | address and the target IP address fields match the address of the 253 | receiving interface, it MUST stop using this address. If this is 254 | the only address of the interface, the interface MUST be turned 255 | down. If there are multiple IP addresses assigned to the 256 | interface, the implementation can choose to only remove the 257 | affected address and keep the interface operating with other 258 | assigned addresses. The host SHOULD report, log, and/or display 259 | messages to indicate the error. If such a reply packet is 260 | received outside the time period, the host SHOULD only report, 261 | log, and/or display messages, but keep operating with the 262 | address. 263 | 264 | 265 | 4. Backwards Compatibility 266 | 267 | The hosts with this solution implemented can coexist with other 268 | hosts that do not have it implemented. The implementation is trivial 269 | and the overhead is very limited. Since one of the primary functions 270 | to fully solve the problem is that the second host stops using the 271 | duplicate IP address, the problem addressed here cannot be 272 | completely avoided unless all hosts on the network follow this 273 | document. However, because many existing TCP/IP implementations 274 | generate gratuitous ARP packet, as well as error reporting when 275 | duplication occurs, running hosts with this solution implemented 276 | can increase the chance of catching the error at earlier stage and 277 | reduce the possible damage made by an error. 278 | 279 | 280 | 5. Security Considerations 281 | 282 | The proposed solution can decrease the impact when a user, either 283 | fraudulently or simply by mistake, configures a host with an existing 284 | IP address on the LAN. Nevertheless, the proposed solution is mainly 285 | designed to prevent configuration errors, not for malicious attacks. 286 | If a hacker can fabricate and transmit ARP packets on a LAN, these 287 | packets can easily confuse all hosts on the LAN and to sabotage any 288 | 289 | 290 | Jou [Page 5] 291 | INTERNET_DRAFT Duplicate IP Address Detection February, 1999 292 | 293 | 294 | network operations. Preventing malicious attacks within a LAN is 295 | sophisticated, and is out of the scope of this document. 296 | 297 | A new security concern introduced by the proposed scheme is by 298 | having a requirement to disable an interface when a suitable ARP 299 | reply is seen. To limit the vulnerability from attacks and network 300 | errors, as described in Step (3) of the solution, this disabling 301 | SHOULD only happen if the reply is received within some time period 302 | of sending out a gratuitous ARP request. A RECOMMENDED default period 303 | is 3 seconds, which is long enough to cover normal operations. 304 | 305 | 306 | 6. Reference 307 | 308 | [1] Plummer, D., "An Ethernet Address Resolution Protocol", STD 37, 309 | RFC 826, MIT, November 1982. 310 | 311 | 312 | 7. Author's Address 313 | 314 | Tyan-Shu Jou 315 | Torrent Networking Technologies Corporation 316 | 3000 Aerial Center Parkway 317 | Suite 140 318 | Morrisville, NC 27560 319 | U.S.A. 320 | 321 | Phone: (919) 468-8466 x233 322 | Email: tsjou@torrentnet.com 323 | 324 | 325 | 8. Full Copyright Statement 326 | 327 | Copyright (C) The Internet Society (1999). All Rights Reserved. 328 | 329 | This document and translations of it may be copied and furnished to 330 | others, and derivative works that comment on or otherwise explain it 331 | or assist in its implementation may be prepared, copied, published and 332 | distributed, in whole or in part, without restriction of any kind, 333 | provided that the above copyright notice and this paragraph are 334 | included on all such copies and derivative works. However, this 335 | document itself may not be modified in any way, such as by removing 336 | the copyright notice or references to the Internet Society or other 337 | Internet organizations, except as needed for the purpose of 338 | developing Internet standards in which case the procedures for 339 | copyrights defined in the Internet Standards process must be 340 | followed, or as required to translate it into languages other than 341 | English. 342 | 343 | The limited permissions granted above are perpetual and will not be 344 | revoked by the Internet Society or its successors or assigns. 345 | 346 | 347 | 348 | Jou [Page 6] 349 | INTERNET_DRAFT Duplicate IP Address Detection February, 1999 350 | 351 | 352 | This document and the information contained herein is provided on an 353 | "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING 354 | TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING 355 | BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION 356 | HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF 357 | MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE." 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | Jou [Page 7] 407 | -------------------------------------------------------------------------------- /doc/principe-Vrrp1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fredbcode/Vrrpd/7988f035835ea614b9b8641c8b1161d9b907c438/doc/principe-Vrrp1.jpg -------------------------------------------------------------------------------- /doc/principe-Vrrp2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fredbcode/Vrrpd/7988f035835ea614b9b8641c8b1161d9b907c438/doc/principe-Vrrp2.jpg -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | PATH=/bin:/usr/bin:/sbin:/usr/sbin 3 | a = 0 4 | 5 | clear 6 | 7 | echo "------------------------------------------------------------------------" 8 | echo " Vrrpd Atropos " 9 | echo "" 10 | echo "" 11 | echo "" 12 | echo "" 13 | echo "" 14 | echo " 1) Compilation " 15 | echo " 2) Compilation & Installation " 16 | echo "" 17 | echo "" 18 | read saisie 19 | case $saisie 20 | in 21 | 1) 22 | echo "compilation" 23 | make clean 24 | make 25 | ;; 26 | 27 | 2) 28 | killall 2>/dev/null 29 | if [ "$?" -ne 1 ] 30 | then 31 | echo "Error: Installation: requires package psmisc (killal)" 32 | exit 0 33 | fi 34 | make clean 35 | make 36 | cp vrrpd /usr/sbin/ 2>/dev/null 37 | cp atropos /usr/sbin/ 2>/dev/null 38 | cp configs/vrrp /etc/init.d/vrrp 2>/dev/null 39 | mkdir -p /etc/vrrpd 2>/dev/null 40 | cp configs/vrrp_on.sh /etc/vrrpd/ 2>/dev/null 41 | cp -Rf configs/vrrpd/* /etc/vrrpd 2>/dev/null 42 | ln -s /etc/vrrpd/vrrp_on.sh /etc/vrrp.conf 2>/dev/null 43 | update-rc.d vrrp defaults 2>/dev/null 44 | echo "Enabling rclevel for vrrp" 45 | 46 | update-rc.d vrrp defaults 2>/dev/null 47 | if [ -d /run/systemd/system ] 48 | then 49 | cp configs/vrrp.service /lib/systemd/system/ 50 | systemctl enable vrrp 51 | systemctl daemon reload 52 | fi 53 | 54 | ;; 55 | 56 | *) # Tous les autres cas 57 | echo " Erreur de saisi";; 58 | esac 59 | -------------------------------------------------------------------------------- /ipaddr.c: -------------------------------------------------------------------------------- 1 | /*===========================[ (c) JME SOFT ]=================================== 2 | FILE : [ipaddr.c] 3 | CREATED : 00/06/02 20:01:59 LAST SAVE : 00/06/02 23:49:56 4 | WHO : jerome@mycpu Linux 2.2.14 5 | REMARK : 6 | ================================================================================ 7 | - highly inspired from ip/ipaddress.c in iproute2 from alexey 8 | ==============================================================================*/ 9 | 10 | /* system 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 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | /* local include */ 32 | #include "libnetlink.h" 33 | 34 | typedef struct { 35 | int ifindex; 36 | uint32_t *addr; 37 | int max_elem; 38 | int nb_elem; 39 | } iplist_ctx; 40 | 41 | /**************************************************************** 42 | NAME : print_addr 00/06/02 18:24:09 43 | AIM : 44 | REMARK : 45 | ****************************************************************/ 46 | static int get_addrinfo(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) 47 | { 48 | struct ifaddrmsg *ifa = NLMSG_DATA(n); 49 | int len = n->nlmsg_len; 50 | iplist_ctx *ctx = (iplist_ctx *)arg; 51 | struct rtattr *rta_tb[IFA_MAX+1]; 52 | /* sanity check */ 53 | len -= NLMSG_LENGTH(sizeof(*ifa)); 54 | if (len < 0) { 55 | fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); 56 | return -1; 57 | } 58 | /* check the message type */ 59 | if (n->nlmsg_type != RTM_NEWADDR ) 60 | return 0; 61 | /* check it is ipv4 */ 62 | if( ifa->ifa_family != AF_INET) 63 | return 0; 64 | /* check it is the good interface */ 65 | if( ifa->ifa_index != ctx->ifindex ) 66 | return 0; 67 | 68 | /* parse the attribute */ 69 | memset(rta_tb, 0, sizeof(rta_tb)); 70 | parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(ifa), len); 71 | 72 | if (!rta_tb[IFA_LOCAL]) 73 | rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS]; 74 | 75 | if (rta_tb[IFA_LOCAL]) { 76 | u_char *src = RTA_DATA(rta_tb[IFA_LOCAL]); 77 | if( ctx->nb_elem >= ctx->max_elem ) 78 | return 0; 79 | ctx->addr[ctx->nb_elem++] = (src[0]<<24) + (src[1]<<16) + 80 | (src[2]<<8) + src[3]; 81 | } 82 | return 0; 83 | } 84 | 85 | 86 | /**************************************************************** 87 | NAME : ipaddr_list 00/06/02 20:02:23 88 | AIM : 89 | REMARK : 90 | ****************************************************************/ 91 | int ipaddr_list( int ifindex, uint32_t *array, int max_elem ) 92 | { 93 | struct rtnl_handle rth; 94 | iplist_ctx ctx; 95 | /* init the struct */ 96 | ctx.ifindex = ifindex; 97 | ctx.addr = array; 98 | ctx.max_elem = max_elem; 99 | ctx.nb_elem = 0; 100 | /* open the rtnetlink socket */ 101 | if( rtnl_open( &rth, 0) ) 102 | return -1; 103 | /* send the request */ 104 | if (rtnl_wilddump_request(&rth, AF_INET, RTM_GETADDR) < 0) { 105 | perror("Cannot send dump request"); 106 | return -1; 107 | } 108 | /* parse the answer */ 109 | if (rtnl_dump_filter(&rth, get_addrinfo, &ctx, NULL, NULL) < 0) { 110 | fprintf(stderr, "Flush terminated\n"); 111 | exit(1); 112 | } 113 | 114 | /* to close the clocket */ 115 | rtnl_close( &rth ); 116 | 117 | return ctx.nb_elem; 118 | } 119 | 120 | 121 | /**************************************************************** 122 | NAME : ipaddr_add 00/06/02 23:00:58 123 | AIM : add or remove 124 | REMARK : 125 | ****************************************************************/ 126 | 127 | int ipaddr_op( int ifindex, uint32_t addr, uint8_t length, int addF ) 128 | { 129 | struct rtnl_handle rth; 130 | struct { 131 | struct nlmsghdr n; 132 | struct ifaddrmsg ifa; 133 | char buf[256]; 134 | } req; 135 | uint32_t bcast; 136 | 137 | memset(&req, 0, sizeof(req)); 138 | 139 | req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); 140 | req.n.nlmsg_flags = NLM_F_REQUEST; 141 | req.n.nlmsg_type = addF ? RTM_NEWADDR : RTM_DELADDR; 142 | req.ifa.ifa_family = AF_INET; 143 | req.ifa.ifa_index = ifindex; 144 | req.ifa.ifa_prefixlen = length; 145 | 146 | addr = htonl( addr ); 147 | addattr_l(&req.n, sizeof(req), IFA_LOCAL, &addr, sizeof(addr) ); 148 | 149 | bcast = addr | htonl((1 << (32 - length)) - 1); 150 | addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &bcast, sizeof(bcast) ); 151 | 152 | 153 | if (rtnl_open(&rth, 0) < 0){ 154 | rtnl_close( &rth ); 155 | return -1; 156 | } 157 | if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) { 158 | rtnl_close( &rth ); 159 | return -1; 160 | } 161 | 162 | /* to close the clocket */ 163 | rtnl_close( &rth ); 164 | 165 | return(0); 166 | } 167 | 168 | -------------------------------------------------------------------------------- /ipaddr.h: -------------------------------------------------------------------------------- 1 | /*===========================[ (c) JME SOFT ]=================================== 2 | FILE : [ipaddr.h] 3 | CREATED : 00/06/02 20:12:33 LAST SAVE : 00/06/02 23:47:42 4 | WHO : jerome@mycpu Linux 2.2.14 5 | REMARK : 6 | ================================================================================ 7 | 8 | ==============================================================================*/ 9 | 10 | #ifndef __IPADDR_H__ 11 | #define __IPADDR_H__ 12 | /* system include */ 13 | /* local include */ 14 | 15 | /*@$#[ipaddr.c] global proto. AutoProtoSigV1.1. date: 00/06/02 23:47:40 */ 16 | #include "proto.h" 17 | int ipaddr_list PROTO((int ifindex, uint32_t *array, int max_elem)); 18 | int ipaddr_op PROTO((int ifindex, uint32_t addr, uint8_t length, int addF)); 19 | 20 | /*@$% end of AutoProtoSigV1.1 (Dont remove this line) []*/ 21 | 22 | 23 | #endif /* __IPADDR_H__ */ 24 | 25 | -------------------------------------------------------------------------------- /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 | #include 24 | #include 25 | 26 | #include "libnetlink.h" 27 | 28 | int rcvbuf = 1024 * 1024; 29 | 30 | #define nl_perror(str) 31 | 32 | void rtnl_close(struct rtnl_handle *rth) 33 | { 34 | if (rth->fd >= 0) { 35 | close(rth->fd); 36 | rth->fd = -1; 37 | } 38 | } 39 | 40 | int rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions, 41 | int protocol) 42 | { 43 | socklen_t addr_len; 44 | int sndbuf = 32768; 45 | 46 | memset(rth, 0, sizeof(*rth)); 47 | 48 | rth->fd = socket(AF_NETLINK, SOCK_RAW, protocol); 49 | if (rth->fd < 0) { 50 | perror("Cannot open netlink socket"); 51 | return -1; 52 | } 53 | 54 | if (setsockopt(rth->fd,SOL_SOCKET,SO_SNDBUF,&sndbuf,sizeof(sndbuf)) < 0) { 55 | perror("SO_SNDBUF"); 56 | return -1; 57 | } 58 | 59 | if (setsockopt(rth->fd,SOL_SOCKET,SO_RCVBUF,&rcvbuf,sizeof(rcvbuf)) < 0) { 60 | perror("SO_RCVBUF"); 61 | return -1; 62 | } 63 | 64 | memset(&rth->local, 0, sizeof(rth->local)); 65 | rth->local.nl_family = AF_NETLINK; 66 | rth->local.nl_groups = subscriptions; 67 | 68 | if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) { 69 | perror("Cannot bind netlink socket"); 70 | return -1; 71 | } 72 | addr_len = sizeof(rth->local); 73 | if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0) { 74 | perror("Cannot getsockname"); 75 | return -1; 76 | } 77 | if (addr_len != sizeof(rth->local)) { 78 | fprintf(stderr, "Wrong address length %d\n", addr_len); 79 | return -1; 80 | } 81 | if (rth->local.nl_family != AF_NETLINK) { 82 | fprintf(stderr, "Wrong address family %d\n", rth->local.nl_family); 83 | return -1; 84 | } 85 | rth->seq = time(NULL); 86 | return 0; 87 | } 88 | 89 | int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions) 90 | { 91 | return rtnl_open_byproto(rth, subscriptions, NETLINK_ROUTE); 92 | } 93 | 94 | int rtnl_wilddump_request(struct rtnl_handle *rth, int family, int type) 95 | { 96 | struct { 97 | struct nlmsghdr nlh; 98 | struct rtgenmsg g; 99 | } req; 100 | 101 | memset(&req, 0, sizeof(req)); 102 | req.nlh.nlmsg_len = sizeof(req); 103 | req.nlh.nlmsg_type = type; 104 | req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST; 105 | req.nlh.nlmsg_pid = 0; 106 | req.nlh.nlmsg_seq = rth->dump = ++rth->seq; 107 | req.g.rtgen_family = family; 108 | 109 | return send(rth->fd, (void*)&req, sizeof(req), 0); 110 | } 111 | 112 | int rtnl_send(struct rtnl_handle *rth, const char *buf, int len) 113 | { 114 | return send(rth->fd, buf, len, 0); 115 | } 116 | 117 | int rtnl_send_check(struct rtnl_handle *rth, const char *buf, int len) 118 | { 119 | struct nlmsghdr *h; 120 | int status; 121 | char resp[1024]; 122 | 123 | status = send(rth->fd, buf, len, 0); 124 | if (status < 0) 125 | return status; 126 | 127 | /* Check for immediate errors */ 128 | status = recv(rth->fd, resp, sizeof(resp), MSG_DONTWAIT|MSG_PEEK); 129 | if (status < 0) { 130 | if (errno == EAGAIN) 131 | return 0; 132 | return -1; 133 | } 134 | 135 | for (h = (struct nlmsghdr *)resp; NLMSG_OK(h, status); 136 | h = NLMSG_NEXT(h, status)) { 137 | if (h->nlmsg_type == NLMSG_ERROR) { 138 | struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); 139 | if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) 140 | fprintf(stderr, "ERROR truncated\n"); 141 | else 142 | errno = -err->error; 143 | return -1; 144 | } 145 | } 146 | 147 | return 0; 148 | } 149 | 150 | int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len) 151 | { 152 | struct nlmsghdr nlh; 153 | struct sockaddr_nl nladdr; 154 | struct iovec iov[2] = { 155 | { .iov_base = &nlh, .iov_len = sizeof(nlh) }, 156 | { .iov_base = req, .iov_len = len } 157 | }; 158 | struct msghdr msg = { 159 | .msg_name = &nladdr, 160 | .msg_namelen = sizeof(nladdr), 161 | .msg_iov = iov, 162 | .msg_iovlen = 2, 163 | }; 164 | 165 | memset(&nladdr, 0, sizeof(nladdr)); 166 | nladdr.nl_family = AF_NETLINK; 167 | 168 | nlh.nlmsg_len = NLMSG_LENGTH(len); 169 | nlh.nlmsg_type = type; 170 | nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|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 | if (a->junk) { 224 | err = a->junk(&nladdr, h, 225 | a->arg2); 226 | if (err < 0) 227 | return err; 228 | } 229 | goto skip_it; 230 | } 231 | 232 | if (h->nlmsg_type == NLMSG_DONE) { 233 | found_done = 1; 234 | break; /* process next filter */ 235 | } 236 | if (h->nlmsg_type == NLMSG_ERROR) { 237 | struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); 238 | if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) { 239 | fprintf(stderr, 240 | "ERROR truncated\n"); 241 | } else { 242 | errno = -err->error; 243 | perror("RTNETLINK answers"); 244 | } 245 | return -1; 246 | } 247 | err = a->filter(&nladdr, h, a->arg1); 248 | if (err < 0) 249 | return err; 250 | 251 | skip_it: 252 | h = NLMSG_NEXT(h, msglen); 253 | } 254 | } 255 | 256 | if (found_done) 257 | return 0; 258 | 259 | if (msg.msg_flags & MSG_TRUNC) { 260 | fprintf(stderr, "Message truncated\n"); 261 | continue; 262 | } 263 | if (msglen) { 264 | fprintf(stderr, "!!!Remnant of size %d\n", msglen); 265 | exit(1); 266 | } 267 | } 268 | } 269 | 270 | int rtnl_dump_filter(struct rtnl_handle *rth, 271 | int (*filter)(struct sockaddr_nl *, struct nlmsghdr *n, void *), 272 | void *arg1, 273 | int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *), 274 | void *arg2) 275 | { 276 | char buf[8192]; 277 | struct sockaddr_nl nladdr; 278 | struct iovec iov = { buf, sizeof(buf) }; 279 | 280 | while (1) { 281 | int status; 282 | struct nlmsghdr *h; 283 | 284 | struct msghdr msg = { 285 | (void*)&nladdr, sizeof(nladdr), 286 | &iov, 1, 287 | NULL, 0, 288 | 0 289 | }; 290 | 291 | status = recvmsg(rth->fd, &msg, 0); 292 | 293 | if (status < 0) { 294 | if (errno == EINTR) 295 | continue; 296 | nl_perror("OVERRUN"); 297 | continue; 298 | } 299 | if (status == 0) { 300 | fprintf(stderr, "EOF on netlink\n"); 301 | return -1; 302 | } 303 | if (msg.msg_namelen != sizeof(nladdr)) { 304 | fprintf(stderr, "sender address length == %d\n", msg.msg_namelen); 305 | exit(1); 306 | } 307 | 308 | h = (struct nlmsghdr*)buf; 309 | while (NLMSG_OK(h, status)) { 310 | int err; 311 | 312 | if (h->nlmsg_pid != rth->local.nl_pid || 313 | h->nlmsg_seq != rth->dump) { 314 | if (junk) { 315 | err = junk(&nladdr, h, arg2); 316 | if (err < 0) 317 | return err; 318 | } 319 | goto skip_it; 320 | } 321 | 322 | if (h->nlmsg_type == NLMSG_DONE) 323 | return 0; 324 | if (h->nlmsg_type == NLMSG_ERROR) { 325 | struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); 326 | if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) { 327 | fprintf(stderr, "ERROR truncated\n"); 328 | } else { 329 | errno = -err->error; 330 | if (errno != EEXIST) 331 | nl_perror("RTNETLINK answers"); 332 | else return 0; 333 | } 334 | return -1; 335 | } 336 | err = filter(&nladdr, h, arg1); 337 | if (err < 0) 338 | return err; 339 | 340 | skip_it: 341 | h = NLMSG_NEXT(h, status); 342 | } 343 | if (msg.msg_flags & MSG_TRUNC) { 344 | fprintf(stderr, "Message truncated\n"); 345 | continue; 346 | } 347 | if (status) { 348 | fprintf(stderr, "!!!Remnant of size %d\n", status); 349 | exit(1); 350 | } 351 | } 352 | } 353 | 354 | int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer, 355 | unsigned groups, struct nlmsghdr *answer, 356 | rtnl_filter_t junk, 357 | void *jarg) 358 | { 359 | int status; 360 | unsigned seq; 361 | struct nlmsghdr *h; 362 | struct sockaddr_nl nladdr; 363 | struct iovec iov = { 364 | .iov_base = (void*) n, 365 | .iov_len = n->nlmsg_len 366 | }; 367 | struct msghdr msg = { 368 | .msg_name = &nladdr, 369 | .msg_namelen = sizeof(nladdr), 370 | .msg_iov = &iov, 371 | .msg_iovlen = 1, 372 | }; 373 | char buf[16384]; 374 | 375 | memset(&nladdr, 0, sizeof(nladdr)); 376 | nladdr.nl_family = AF_NETLINK; 377 | nladdr.nl_pid = peer; 378 | nladdr.nl_groups = groups; 379 | 380 | n->nlmsg_seq = seq = ++rtnl->seq; 381 | 382 | if (answer == NULL) 383 | n->nlmsg_flags |= NLM_F_ACK; 384 | 385 | status = sendmsg(rtnl->fd, &msg, 0); 386 | 387 | if (status < 0) { 388 | perror("Cannot talk to rtnetlink"); 389 | return -1; 390 | } 391 | 392 | memset(buf,0,sizeof(buf)); 393 | 394 | iov.iov_base = buf; 395 | 396 | while (1) { 397 | iov.iov_len = sizeof(buf); 398 | status = recvmsg(rtnl->fd, &msg, 0); 399 | 400 | if (status < 0) { 401 | if (errno == EINTR || errno == EAGAIN) 402 | continue; 403 | fprintf(stderr, "netlink receive error %s (%d)\n", 404 | strerror(errno), errno); 405 | return -1; 406 | } 407 | if (status == 0) { 408 | fprintf(stderr, "EOF on netlink\n"); 409 | return -1; 410 | } 411 | if (msg.msg_namelen != sizeof(nladdr)) { 412 | fprintf(stderr, "sender address length == %d\n", msg.msg_namelen); 413 | exit(1); 414 | } 415 | for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) { 416 | int err; 417 | int len = h->nlmsg_len; 418 | int l = len - sizeof(*h); 419 | 420 | if (l<0 || len>status) { 421 | if (msg.msg_flags & MSG_TRUNC) { 422 | fprintf(stderr, "Truncated message\n"); 423 | return -1; 424 | } 425 | fprintf(stderr, "!!!malformed message: len=%d\n", len); 426 | exit(1); 427 | } 428 | 429 | if (nladdr.nl_pid != peer || 430 | h->nlmsg_pid != rtnl->local.nl_pid || 431 | h->nlmsg_seq != seq) { 432 | if (junk) { 433 | err = junk(&nladdr, h, jarg); 434 | if (err < 0) 435 | return err; 436 | } 437 | /* Don't forget to skip that message. */ 438 | status -= NLMSG_ALIGN(len); 439 | h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); 440 | continue; 441 | } 442 | 443 | if (h->nlmsg_type == NLMSG_ERROR) { 444 | struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); 445 | if (l < sizeof(struct nlmsgerr)) { 446 | fprintf(stderr, "ERROR truncated\n"); 447 | } else { 448 | errno = -err->error; 449 | if (errno == 0) { 450 | if (answer) 451 | memcpy(answer, h, h->nlmsg_len); 452 | return 0; 453 | } 454 | perror("RTNETLINK answers"); 455 | } 456 | return -1; 457 | } 458 | if (answer) { 459 | memcpy(answer, h, h->nlmsg_len); 460 | return 0; 461 | } 462 | 463 | fprintf(stderr, "Unexpected reply!!!\n"); 464 | 465 | status -= NLMSG_ALIGN(len); 466 | h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); 467 | } 468 | if (msg.msg_flags & MSG_TRUNC) { 469 | fprintf(stderr, "Message truncated\n"); 470 | continue; 471 | } 472 | if (status) { 473 | fprintf(stderr, "!!!Remnant of size %d\n", status); 474 | exit(1); 475 | } 476 | } 477 | } 478 | 479 | int rtnl_listen(struct rtnl_handle *rtnl, 480 | rtnl_filter_t handler, 481 | void *jarg) 482 | { 483 | int status; 484 | struct nlmsghdr *h; 485 | struct sockaddr_nl nladdr; 486 | struct iovec iov; 487 | struct msghdr msg = { 488 | .msg_name = &nladdr, 489 | .msg_namelen = sizeof(nladdr), 490 | .msg_iov = &iov, 491 | .msg_iovlen = 1, 492 | }; 493 | char buf[8192]; 494 | 495 | memset(&nladdr, 0, sizeof(nladdr)); 496 | nladdr.nl_family = AF_NETLINK; 497 | nladdr.nl_pid = 0; 498 | nladdr.nl_groups = 0; 499 | 500 | iov.iov_base = buf; 501 | while (1) { 502 | iov.iov_len = sizeof(buf); 503 | status = recvmsg(rtnl->fd, &msg, 0); 504 | 505 | if (status < 0) { 506 | if (errno == EINTR || errno == EAGAIN) 507 | continue; 508 | fprintf(stderr, "netlink receive error %s (%d)\n", 509 | strerror(errno), errno); 510 | if (errno == ENOBUFS) 511 | continue; 512 | return -1; 513 | } 514 | if (status == 0) { 515 | fprintf(stderr, "EOF on netlink\n"); 516 | return -1; 517 | } 518 | if (msg.msg_namelen != sizeof(nladdr)) { 519 | fprintf(stderr, "Sender address length == %d\n", msg.msg_namelen); 520 | exit(1); 521 | } 522 | for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) { 523 | int err; 524 | int len = h->nlmsg_len; 525 | int l = len - sizeof(*h); 526 | 527 | if (l<0 || len>status) { 528 | if (msg.msg_flags & MSG_TRUNC) { 529 | fprintf(stderr, "Truncated message\n"); 530 | return -1; 531 | } 532 | fprintf(stderr, "!!!malformed message: len=%d\n", len); 533 | exit(1); 534 | } 535 | 536 | err = handler(&nladdr, h, jarg); 537 | if (err < 0) 538 | return err; 539 | 540 | status -= NLMSG_ALIGN(len); 541 | h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); 542 | } 543 | if (msg.msg_flags & MSG_TRUNC) { 544 | fprintf(stderr, "Message truncated\n"); 545 | continue; 546 | } 547 | if (status) { 548 | fprintf(stderr, "!!!Remnant of size %d\n", status); 549 | exit(1); 550 | } 551 | } 552 | } 553 | 554 | int rtnl_from_file(FILE *rtnl, rtnl_filter_t handler, 555 | void *jarg) 556 | { 557 | int status; 558 | struct sockaddr_nl nladdr; 559 | char buf[8192]; 560 | struct nlmsghdr *h = (void*)buf; 561 | 562 | memset(&nladdr, 0, sizeof(nladdr)); 563 | nladdr.nl_family = AF_NETLINK; 564 | nladdr.nl_pid = 0; 565 | nladdr.nl_groups = 0; 566 | 567 | while (1) { 568 | int err, len, l; 569 | 570 | status = fread(&buf, 1, sizeof(*h), rtnl); 571 | 572 | if (status < 0) { 573 | if (errno == EINTR) 574 | continue; 575 | perror("rtnl_from_file: fread"); 576 | return -1; 577 | } 578 | if (status == 0) 579 | return 0; 580 | 581 | len = h->nlmsg_len; 582 | l = len - sizeof(*h); 583 | 584 | if (l<0 || len>sizeof(buf)) { 585 | fprintf(stderr, "!!!malformed message: len=%d @%lu\n", 586 | len, ftell(rtnl)); 587 | return -1; 588 | } 589 | 590 | status = fread(NLMSG_DATA(h), 1, NLMSG_ALIGN(l), rtnl); 591 | 592 | if (status < 0) { 593 | perror("rtnl_from_file: fread"); 594 | return -1; 595 | } 596 | if (status < l) { 597 | fprintf(stderr, "rtnl-from_file: truncated message\n"); 598 | return -1; 599 | } 600 | 601 | err = handler(&nladdr, h, jarg); 602 | if (err < 0) 603 | return err; 604 | } 605 | } 606 | 607 | int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data) 608 | { 609 | int len = RTA_LENGTH(4); 610 | struct rtattr *rta; 611 | if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen) { 612 | fprintf(stderr,"addattr32: Error! max allowed bound %d exceeded\n",maxlen); 613 | return -1; 614 | } 615 | rta = NLMSG_TAIL(n); 616 | rta->rta_type = type; 617 | rta->rta_len = len; 618 | memcpy(RTA_DATA(rta), &data, 4); 619 | n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len; 620 | return 0; 621 | } 622 | 623 | int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data, 624 | int alen) 625 | { 626 | int len = RTA_LENGTH(alen); 627 | struct rtattr *rta; 628 | 629 | if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) { 630 | fprintf(stderr, "addattr_l ERROR: message exceeded bound of %d\n",maxlen); 631 | return -1; 632 | } 633 | rta = NLMSG_TAIL(n); 634 | rta->rta_type = type; 635 | rta->rta_len = len; 636 | memcpy(RTA_DATA(rta), data, alen); 637 | n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len); 638 | return 0; 639 | } 640 | 641 | int addraw_l(struct nlmsghdr *n, int maxlen, const void *data, int len) 642 | { 643 | if (NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len) > maxlen) { 644 | fprintf(stderr, "addraw_l ERROR: message exceeded bound of %d\n",maxlen); 645 | return -1; 646 | } 647 | 648 | memcpy(NLMSG_TAIL(n), data, len); 649 | memset((void *) NLMSG_TAIL(n) + len, 0, NLMSG_ALIGN(len) - len); 650 | n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len); 651 | return 0; 652 | } 653 | 654 | struct rtattr *addattr_nest(struct nlmsghdr *n, int maxlen, int type) 655 | { 656 | struct rtattr *nest = NLMSG_TAIL(n); 657 | 658 | addattr_l(n, maxlen, type, NULL, 0); 659 | return nest; 660 | } 661 | 662 | int addattr_nest_end(struct nlmsghdr *n, struct rtattr *nest) 663 | { 664 | nest->rta_len = (void *)NLMSG_TAIL(n) - (void *)nest; 665 | return n->nlmsg_len; 666 | } 667 | 668 | struct rtattr *addattr_nest_compat(struct nlmsghdr *n, int maxlen, int type, 669 | const void *data, int len) 670 | { 671 | struct rtattr *start = NLMSG_TAIL(n); 672 | 673 | addattr_l(n, maxlen, type, data, len); 674 | addattr_nest(n, maxlen, type); 675 | return start; 676 | } 677 | 678 | int addattr_nest_compat_end(struct nlmsghdr *n, struct rtattr *start) 679 | { 680 | struct rtattr *nest = (void *)start + NLMSG_ALIGN(start->rta_len); 681 | 682 | start->rta_len = (void *)NLMSG_TAIL(n) - (void *)start; 683 | addattr_nest_end(n, nest); 684 | return n->nlmsg_len; 685 | } 686 | 687 | int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data) 688 | { 689 | int len = RTA_LENGTH(4); 690 | struct rtattr *subrta; 691 | 692 | if (RTA_ALIGN(rta->rta_len) + len > maxlen) { 693 | fprintf(stderr,"rta_addattr32: Error! max allowed bound %d exceeded\n",maxlen); 694 | return -1; 695 | } 696 | subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len)); 697 | subrta->rta_type = type; 698 | subrta->rta_len = len; 699 | memcpy(RTA_DATA(subrta), &data, 4); 700 | rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len; 701 | return 0; 702 | } 703 | 704 | int rta_addattr_l(struct rtattr *rta, int maxlen, int type, 705 | const void *data, int alen) 706 | { 707 | struct rtattr *subrta; 708 | int len = RTA_LENGTH(alen); 709 | 710 | if (RTA_ALIGN(rta->rta_len) + RTA_ALIGN(len) > maxlen) { 711 | fprintf(stderr,"rta_addattr_l: Error! max allowed bound %d exceeded\n",maxlen); 712 | return -1; 713 | } 714 | subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len)); 715 | subrta->rta_type = type; 716 | subrta->rta_len = len; 717 | memcpy(RTA_DATA(subrta), data, alen); 718 | rta->rta_len = NLMSG_ALIGN(rta->rta_len) + RTA_ALIGN(len); 719 | return 0; 720 | } 721 | 722 | int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) 723 | { 724 | memset(tb, 0, sizeof(struct rtattr *) * (max + 1)); 725 | while (RTA_OK(rta, len)) { 726 | if ((rta->rta_type <= max) && (!tb[rta->rta_type])) 727 | tb[rta->rta_type] = rta; 728 | rta = RTA_NEXT(rta,len); 729 | } 730 | if (len) 731 | fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len); 732 | return 0; 733 | } 734 | 735 | int parse_rtattr_byindex(struct rtattr *tb[], int max, struct rtattr *rta, int len) 736 | { 737 | int i = 0; 738 | 739 | memset(tb, 0, sizeof(struct rtattr *) * max); 740 | while (RTA_OK(rta, len)) { 741 | if (rta->rta_type <= max && i < max) 742 | tb[i++] = rta; 743 | rta = RTA_NEXT(rta,len); 744 | } 745 | if (len) 746 | fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len); 747 | return i; 748 | } 749 | 750 | int __parse_rtattr_nested_compat(struct rtattr *tb[], int max, struct rtattr *rta, 751 | int len) 752 | { 753 | if (RTA_PAYLOAD(rta) < len) 754 | return -1; 755 | if (RTA_PAYLOAD(rta) >= RTA_ALIGN(len) + sizeof(struct rtattr)) { 756 | rta = RTA_DATA(rta) + RTA_ALIGN(len); 757 | return parse_rtattr_nested(tb, max, rta); 758 | } 759 | memset(tb, 0, sizeof(struct rtattr *) * (max + 1)); 760 | return 0; 761 | } 762 | -------------------------------------------------------------------------------- /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 | 11 | struct rtnl_handle 12 | { 13 | int fd; 14 | struct sockaddr_nl local; 15 | struct sockaddr_nl peer; 16 | __u32 seq; 17 | __u32 dump; 18 | }; 19 | 20 | extern int rcvbuf; 21 | 22 | extern int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions); 23 | extern int rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions, int protocol); 24 | extern void rtnl_close(struct rtnl_handle *rth); 25 | extern int rtnl_wilddump_request(struct rtnl_handle *rth, int fam, int type); 26 | extern int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len); 27 | 28 | typedef int (*rtnl_filter_t)(const struct sockaddr_nl *, 29 | struct nlmsghdr *n, void *); 30 | 31 | struct rtnl_dump_filter_arg 32 | { 33 | rtnl_filter_t filter; 34 | void *arg1; 35 | rtnl_filter_t junk; 36 | void *arg2; 37 | }; 38 | 39 | extern int rtnl_dump_filter_l(struct rtnl_handle *rth, 40 | const struct rtnl_dump_filter_arg *arg); 41 | 42 | extern int rtnl_dump_filter(struct rtnl_handle *rth, 43 | int (*filter)(struct sockaddr_nl *, struct nlmsghdr *n, void *), 44 | void *arg1, 45 | int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *), 46 | void *arg2); 47 | 48 | extern int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer, 49 | unsigned groups, struct nlmsghdr *answer, 50 | rtnl_filter_t junk, 51 | void *jarg); 52 | extern int rtnl_send(struct rtnl_handle *rth, const char *buf, int); 53 | extern int rtnl_send_check(struct rtnl_handle *rth, const char *buf, int); 54 | 55 | extern int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data); 56 | extern int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data, int alen); 57 | extern int addraw_l(struct nlmsghdr *n, int maxlen, const void *data, int len); 58 | extern struct rtattr *addattr_nest(struct nlmsghdr *n, int maxlen, int type); 59 | extern int addattr_nest_end(struct nlmsghdr *n, struct rtattr *nest); 60 | extern struct rtattr *addattr_nest_compat(struct nlmsghdr *n, int maxlen, int type, const void *data, int len); 61 | extern int addattr_nest_compat_end(struct nlmsghdr *n, struct rtattr *nest); 62 | extern int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data); 63 | extern int rta_addattr_l(struct rtattr *rta, int maxlen, int type, const void *data, int alen); 64 | 65 | extern int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len); 66 | extern int parse_rtattr_byindex(struct rtattr *tb[], int max, struct rtattr *rta, int len); 67 | extern int __parse_rtattr_nested_compat(struct rtattr *tb[], int max, struct rtattr *rta, int len); 68 | 69 | #define parse_rtattr_nested(tb, max, rta) \ 70 | (parse_rtattr((tb), (max), RTA_DATA(rta), RTA_PAYLOAD(rta))) 71 | 72 | #define parse_rtattr_nested_compat(tb, max, rta, data, len) \ 73 | ({ data = RTA_PAYLOAD(rta) >= len ? RTA_DATA(rta) : NULL; \ 74 | __parse_rtattr_nested_compat(tb, max, rta, len); }) 75 | 76 | extern int rtnl_listen(struct rtnl_handle *, rtnl_filter_t handler, 77 | void *jarg); 78 | extern int rtnl_from_file(FILE *, rtnl_filter_t handler, 79 | void *jarg); 80 | 81 | #define NLMSG_TAIL(nmsg) \ 82 | ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) 83 | 84 | #ifndef IFA_RTA 85 | #define IFA_RTA(r) \ 86 | ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg)))) 87 | #endif 88 | #ifndef IFA_PAYLOAD 89 | #define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrmsg)) 90 | #endif 91 | 92 | #ifndef IFLA_RTA 93 | #define IFLA_RTA(r) \ 94 | ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg)))) 95 | #endif 96 | #ifndef IFLA_PAYLOAD 97 | #define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg)) 98 | #endif 99 | 100 | #ifndef NDA_RTA 101 | #define NDA_RTA(r) \ 102 | ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg)))) 103 | #endif 104 | #ifndef NDA_PAYLOAD 105 | #define NDA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ndmsg)) 106 | #endif 107 | 108 | #ifndef NDTA_RTA 109 | #define NDTA_RTA(r) \ 110 | ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndtmsg)))) 111 | #endif 112 | #ifndef NDTA_PAYLOAD 113 | #define NDTA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ndtmsg)) 114 | #endif 115 | 116 | #endif /* __LIBNETLINK_H__ */ 117 | 118 | -------------------------------------------------------------------------------- /ll_map.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ll_map.c 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 | 22 | #include "libnetlink.h" 23 | #include "ll_map.h" 24 | 25 | struct idxmap 26 | { 27 | struct idxmap * next; 28 | int index; 29 | int type; 30 | int alen; 31 | unsigned flags; 32 | unsigned char addr[8]; 33 | char name[16]; 34 | }; 35 | 36 | static struct idxmap *idxmap[16]; 37 | 38 | int ll_remember_index(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) 39 | { 40 | int h; 41 | struct ifinfomsg *ifi = NLMSG_DATA(n); 42 | struct idxmap *im, **imp; 43 | struct rtattr *tb[IFLA_MAX+1]; 44 | 45 | if (n->nlmsg_type != RTM_NEWLINK) 46 | return 0; 47 | 48 | if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifi))) 49 | return -1; 50 | 51 | 52 | memset(tb, 0, sizeof(tb)); 53 | parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(n)); 54 | if (tb[IFLA_IFNAME] == NULL) 55 | return 0; 56 | 57 | h = ifi->ifi_index&0xF; 58 | 59 | for (imp=&idxmap[h]; (im=*imp)!=NULL; imp = &im->next) 60 | if (im->index == ifi->ifi_index) 61 | break; 62 | 63 | if (im == NULL) { 64 | im = malloc(sizeof(*im)); 65 | if (im == NULL) 66 | return 0; 67 | im->next = *imp; 68 | im->index = ifi->ifi_index; 69 | *imp = im; 70 | } 71 | 72 | im->type = ifi->ifi_type; 73 | im->flags = ifi->ifi_flags; 74 | if (tb[IFLA_ADDRESS]) { 75 | int alen; 76 | im->alen = alen = RTA_PAYLOAD(tb[IFLA_ADDRESS]); 77 | if (alen > sizeof(im->addr)) 78 | alen = sizeof(im->addr); 79 | memcpy(im->addr, RTA_DATA(tb[IFLA_ADDRESS]), alen); 80 | } else { 81 | im->alen = 0; 82 | memset(im->addr, 0, sizeof(im->addr)); 83 | } 84 | strcpy(im->name, RTA_DATA(tb[IFLA_IFNAME])); 85 | return 0; 86 | } 87 | 88 | const char *ll_idx_n2a(int idx, char *buf) 89 | { 90 | struct idxmap *im; 91 | 92 | if (idx == 0) 93 | return "*"; 94 | for (im = idxmap[idx&0xF]; im; im = im->next) 95 | if (im->index == idx) 96 | return im->name; 97 | snprintf(buf, 16, "if%d", idx); 98 | return buf; 99 | } 100 | 101 | 102 | const char *ll_index_to_name(int idx) 103 | { 104 | static char nbuf[16]; 105 | 106 | return ll_idx_n2a(idx, nbuf); 107 | } 108 | 109 | int ll_index_to_type(int idx) 110 | { 111 | struct idxmap *im; 112 | 113 | if (idx == 0) 114 | return -1; 115 | for (im = idxmap[idx&0xF]; im; im = im->next) 116 | if (im->index == idx) 117 | return im->type; 118 | return -1; 119 | } 120 | 121 | unsigned ll_index_to_flags(int idx) 122 | { 123 | struct idxmap *im; 124 | 125 | if (idx == 0) 126 | return 0; 127 | 128 | for (im = idxmap[idx&0xF]; im; im = im->next) 129 | if (im->index == idx) 130 | return im->flags; 131 | return 0; 132 | } 133 | 134 | int ll_name_to_index(char *name) 135 | { 136 | static char ncache[16]; 137 | static int icache; 138 | struct idxmap *im; 139 | int i; 140 | 141 | if (name == NULL) 142 | return 0; 143 | if (icache && strcmp(name, ncache) == 0) 144 | return icache; 145 | for (i=0; i<16; i++) { 146 | for (im = idxmap[i]; im; im = im->next) { 147 | if (strcmp(im->name, name) == 0) { 148 | icache = im->index; 149 | strcpy(ncache, name); 150 | return im->index; 151 | } 152 | } 153 | } 154 | return 0; 155 | } 156 | 157 | int ll_init_map(struct rtnl_handle *rth) 158 | { 159 | if (rtnl_wilddump_request(rth, AF_UNSPEC, RTM_GETLINK) < 0) { 160 | perror("Cannot send dump request"); 161 | exit(1); 162 | } 163 | 164 | if (rtnl_dump_filter(rth, ll_remember_index, &idxmap, NULL, NULL) < 0) { 165 | fprintf(stderr, "Dump terminated\n"); 166 | exit(1); 167 | } 168 | return 0; 169 | } 170 | -------------------------------------------------------------------------------- /proto.h: -------------------------------------------------------------------------------- 1 | /*=========================[ (c) POIPOI SOFT ]================================== 2 | 3 | FILE : [protodef.h] 4 | 5 | DATE : 95/11/10 22:44:23 6 | 7 | WHO : poipoi@hwi.resi.insa-lyon.fr Linux 1.2.13 8 | 9 | REMARK : 10 | 11 | ================================================================================ 12 | 13 | ==============================================================================*/ 14 | 15 | #ifndef __PROTODEF_H__ 16 | #define __PROTODEF_H__ 17 | #ifndef PROTO 18 | #if __STDC__ 19 | # define PROTO(x) x 20 | #else 21 | # define PROTO(x) () 22 | #endif 23 | #endif 24 | 25 | #endif /* __PROTODEF_H__ */ 26 | 27 | -------------------------------------------------------------------------------- /route.generic: -------------------------------------------------------------------------------- 1 | diff -ru -x*~ linux-lt-2.3.99-pre3.prev/Documentation/networking/ip-sysctl.txt linux-lt-2.3.99-pre3/Documentation/networking/ip-sysctl.txt 2 | --- linux-lt-2.3.99-pre3.prev/Documentation/networking/ip-sysctl.txt Sun Jan 23 03:54:56 2000 3 | +++ linux-lt-2.3.99-pre3/Documentation/networking/ip-sysctl.txt Tue Mar 28 19:40:59 2000 4 | @@ -262,13 +262,21 @@ 5 | Do proxy arp. 6 | 7 | shared_media - BOOLEAN 8 | - Send(router) or accept(host) RFC1620 shared media redirects. 9 | + Do not check the new gateway specified in incoming ICMP redirect 10 | + messages for belonging to a directly attached network (i.e. the 11 | + routing table has for this address an entry pointing to the given 12 | + device, doesn't have a gateway, and with scope not wider SCOPE_LINK). 13 | + If this variable is TRUE then new gateways are only checked for being a 14 | + unicast addresses. If it is FALSE then the full check described 15 | + above is performed. See RFC1620 for background information about 16 | + shared media. 17 | Overrides ip_secure_redirects. 18 | default TRUE 19 | 20 | secure_redirects - BOOLEAN 21 | - Accept ICMP redirect messages only for gateways, 22 | - listed in default gateway list. 23 | + Accept ICMP redirect messages only for gateways already listed as 24 | + gateways in the routing tables. This check is performed only when 25 | + `shared_media' is FALSE. 26 | default TRUE 27 | 28 | send_redirects - BOOLEAN 29 | @@ -287,6 +295,19 @@ 30 | default TRUE (router) 31 | FALSE (host) 32 | 33 | +source_check - BOOLEAN 34 | + Check source address for outgoing packets. 35 | + If source_check is turned on all outgoing packets (including going 36 | + through a loopback interface) are checked for the source address 37 | + being local. An address is considered as local for this purposes if 38 | + a route lookup in the opposite direction (i.e. with source and 39 | + destination addresses being reversed) gives a unicast local route 40 | + entry. 41 | + Note: source addresses are always checked for being not a multicast, 42 | + limited broadcast, zero net, or loopback (for non-loopback 43 | + interfaces) independetly of the setting of the option. 44 | + default TRUE 45 | + 46 | rp_filter - BOOLEAN 47 | 1 - do source validation by reversed path, as specified in RFC1812 48 | Recommended option for single homed hosts and stub network 49 | @@ -305,4 +326,8 @@ 50 | Updated by: 51 | Andi Kleen 52 | ak@muc.de 53 | + 54 | +Andrey Savochkin 55 | +saw@msu.ru 56 | + 57 | $Id: route.generic,v 1.1.1.1 2002/09/09 14:51:13 imagestream Exp $ 58 | diff -ru -x*~ linux-lt-2.3.99-pre3.prev/include/linux/in_route.h linux-lt-2.3.99-pre3/include/linux/in_route.h 59 | --- linux-lt-2.3.99-pre3.prev/include/linux/in_route.h Fri Jun 12 13:52:33 1998 60 | +++ linux-lt-2.3.99-pre3/include/linux/in_route.h Tue Mar 28 19:39:49 2000 61 | @@ -4,6 +4,7 @@ 62 | /* IPv4 routing cache flags */ 63 | 64 | #define RTCF_DEAD RTNH_F_DEAD 65 | +#define RTCF_PERVASIVE RTNH_F_PERVASIVE 66 | #define RTCF_ONLINK RTNH_F_ONLINK 67 | 68 | /* Obsolete flag. About to be deleted */ 69 | diff -ru -x*~ linux-lt-2.3.99-pre3.prev/include/linux/inetdevice.h linux-lt-2.3.99-pre3/include/linux/inetdevice.h 70 | --- linux-lt-2.3.99-pre3.prev/include/linux/inetdevice.h Tue Aug 24 01:01:02 1999 71 | +++ linux-lt-2.3.99-pre3/include/linux/inetdevice.h Tue Mar 28 19:39:49 2000 72 | @@ -9,6 +9,7 @@ 73 | int send_redirects; 74 | int secure_redirects; 75 | int shared_media; 76 | + int source_check; 77 | int accept_source_route; 78 | int rp_filter; 79 | int proxy_arp; 80 | @@ -46,6 +47,7 @@ 81 | #define IN_DEV_SHARED_MEDIA(in_dev) (ipv4_devconf.shared_media || (in_dev)->cnf.shared_media) 82 | #define IN_DEV_TX_REDIRECTS(in_dev) (ipv4_devconf.send_redirects || (in_dev)->cnf.send_redirects) 83 | #define IN_DEV_SEC_REDIRECTS(in_dev) (ipv4_devconf.secure_redirects || (in_dev)->cnf.secure_redirects) 84 | +#define IN_DEV_SRC_CHECK(in_dev) (ipv4_devconf.source_check || (in_dev)->cnf.source_check) 85 | #define IN_DEV_IDTAG(in_dev) ((in_dev)->cnf.tag) 86 | 87 | #define IN_DEV_RX_REDIRECTS(in_dev) \ 88 | @@ -73,7 +75,6 @@ 89 | extern int unregister_inetaddr_notifier(struct notifier_block *nb); 90 | 91 | extern struct net_device *ip_dev_find(u32 addr); 92 | -extern int inet_addr_onlink(struct in_device *in_dev, u32 a, u32 b); 93 | extern int devinet_ioctl(unsigned int cmd, void *); 94 | extern void devinet_init(void); 95 | extern struct in_device *inetdev_init(struct net_device *dev); 96 | diff -ru -x*~ linux-lt-2.3.99-pre3.prev/include/linux/rtnetlink.h linux-lt-2.3.99-pre3/include/linux/rtnetlink.h 97 | --- linux-lt-2.3.99-pre3.prev/include/linux/rtnetlink.h Thu Feb 10 12:08:09 2000 98 | +++ linux-lt-2.3.99-pre3/include/linux/rtnetlink.h Tue Mar 28 19:39:49 2000 99 | @@ -224,9 +224,11 @@ 100 | 101 | /* rtnh_flags */ 102 | 103 | -#define RTNH_F_DEAD 1 /* Nexthop is dead (used by multipath) */ 104 | -#define RTNH_F_PERVASIVE 2 /* Do recursive gateway lookup */ 105 | -#define RTNH_F_ONLINK 4 /* Gateway is forced on link */ 106 | +#define RTNH_F_DEAD 0x01 /* Nexthop is dead (used by multipath) */ 107 | +#define RTNH_F_PERVASIVE 0x02 /* Omit gateway & pref_src test */ 108 | +#define RTNH_F_ONLINK 0x04 /* Gateway is forced on link */ 109 | +#define RTNH_F_GLUE 0x08 /* Nexthop is glued */ 110 | +#define RTNH_F_USEFIRST 0x10 /* Use only it (for multipath) */ 111 | 112 | /* Macros to handle hexthops */ 113 | 114 | diff -ru -x*~ linux-lt-2.3.99-pre3.prev/include/linux/sysctl.h linux-lt-2.3.99-pre3/include/linux/sysctl.h 115 | --- linux-lt-2.3.99-pre3.prev/include/linux/sysctl.h Thu Mar 9 01:16:24 2000 116 | +++ linux-lt-2.3.99-pre3/include/linux/sysctl.h Tue Mar 28 19:39:49 2000 117 | @@ -302,7 +302,8 @@ 118 | NET_IPV4_CONF_ACCEPT_SOURCE_ROUTE=9, 119 | NET_IPV4_CONF_BOOTP_RELAY=10, 120 | NET_IPV4_CONF_LOG_MARTIANS=11, 121 | - NET_IPV4_CONF_TAG=12 122 | + NET_IPV4_CONF_TAG=12, 123 | + NET_IPV4_CONF_SRC_CHECK=13, 124 | }; 125 | 126 | /* /proc/sys/net/ipv6 */ 127 | diff -ru -x*~ linux-lt-2.3.99-pre3.prev/include/net/ip_fib.h linux-lt-2.3.99-pre3/include/net/ip_fib.h 128 | --- linux-lt-2.3.99-pre3.prev/include/net/ip_fib.h Tue Aug 24 01:01:02 1999 129 | +++ linux-lt-2.3.99-pre3/include/net/ip_fib.h Tue Mar 28 19:39:49 2000 130 | @@ -217,7 +217,8 @@ 131 | extern int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event, 132 | u8 tb_id, u8 type, u8 scope, void *dst, int dst_len, u8 tos, 133 | struct fib_info *fi); 134 | -extern int fib_sync_down(u32 local, struct net_device *dev, int force); 135 | +extern int fib_sync_addr_down(u32 local); 136 | +extern int fib_sync_dev_down(struct net_device *dev, int force); 137 | extern int fib_sync_up(struct net_device *dev); 138 | extern int fib_convert_rtentry(int cmd, struct nlmsghdr *nl, struct rtmsg *rtm, 139 | struct kern_rta *rta, struct rtentry *r); 140 | diff -ru -x*~ linux-lt-2.3.99-pre3.prev/include/net/route.h linux-lt-2.3.99-pre3/include/net/route.h 141 | --- linux-lt-2.3.99-pre3.prev/include/net/route.h Sun Mar 19 04:11:22 2000 142 | +++ linux-lt-2.3.99-pre3/include/net/route.h Tue Mar 28 19:39:49 2000 143 | @@ -106,6 +106,9 @@ 144 | extern void ip_rt_send_redirect(struct sk_buff *skb); 145 | 146 | extern unsigned inet_addr_type(u32 addr); 147 | +extern int inet_addr_onlink(struct net_device *, u32 dst, u32 src, u8 tos); 148 | +extern int fib_local_source(u32 saddr, u32 daddr, u8 tos, struct net_device *); 149 | +extern u32 fib_select_addr(struct net_device *, u32 dst, int scope); 150 | extern void ip_rt_multicast_event(struct in_device *); 151 | extern int ip_rt_ioctl(unsigned int cmd, void *arg); 152 | extern void ip_rt_get_source(u8 *src, struct rtable *rt); 153 | diff -ru -x*~ linux-lt-2.3.99-pre3.prev/net/ipv4/af_inet.c linux-lt-2.3.99-pre3/net/ipv4/af_inet.c 154 | --- linux-lt-2.3.99-pre3.prev/net/ipv4/af_inet.c Tue Feb 22 09:35:06 2000 155 | +++ linux-lt-2.3.99-pre3/net/ipv4/af_inet.c Tue Mar 28 19:43:30 2000 156 | @@ -463,6 +463,15 @@ 157 | return -EINVAL; 158 | 159 | chk_addr_ret = inet_addr_type(addr->sin_addr.s_addr); 160 | + /* The source address check is omitted here. 161 | + * We may allow to bind sockets to any address for listening purposes. 162 | + * Such sockets will get only those packets which were considered as 163 | + * "local" by routing (i.e. configured to go locally by the 164 | + * administrator). 165 | + * Outgoing packets are checked by output routing (see 166 | + * ip_route_output_slow and outrt_check_src in net/ipv4/route.c). 167 | + * 1999/11/13 SAW 168 | + */ 169 | 170 | snum = ntohs(addr->sin_port); 171 | if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) 172 | diff -ru -x*~ linux-lt-2.3.99-pre3.prev/net/ipv4/arp.c linux-lt-2.3.99-pre3/net/ipv4/arp.c 173 | --- linux-lt-2.3.99-pre3.prev/net/ipv4/arp.c Sun Jan 23 03:54:57 2000 174 | +++ linux-lt-2.3.99-pre3/net/ipv4/arp.c Tue Mar 28 19:39:50 2000 175 | @@ -333,10 +333,11 @@ 176 | u32 target = *(u32*)neigh->primary_key; 177 | int probes = atomic_read(&neigh->probes); 178 | 179 | - if (skb && inet_addr_type(skb->nh.iph->saddr) == RTN_LOCAL) 180 | + if (skb && fib_local_source(skb->nh.iph->saddr, target, 181 | + skb->nh.iph->tos, dev) == 0) 182 | saddr = skb->nh.iph->saddr; 183 | else 184 | - saddr = inet_select_addr(dev, target, RT_SCOPE_LINK); 185 | + saddr = fib_select_addr(dev, target, RT_SCOPE_LINK); 186 | 187 | if ((probes -= neigh->parms->ucast_probes) < 0) { 188 | if (!(neigh->nud_state&NUD_VALID)) 189 | diff -ru -x*~ linux-lt-2.3.99-pre3.prev/net/ipv4/devinet.c linux-lt-2.3.99-pre3/net/ipv4/devinet.c 190 | --- linux-lt-2.3.99-pre3.prev/net/ipv4/devinet.c Sun Jan 9 13:36:20 2000 191 | +++ linux-lt-2.3.99-pre3/net/ipv4/devinet.c Tue Mar 28 19:39:50 2000 192 | @@ -58,8 +58,8 @@ 193 | #include 194 | #include 195 | 196 | -struct ipv4_devconf ipv4_devconf = { 1, 1, 1, 1, 0, }; 197 | -static struct ipv4_devconf ipv4_devconf_dflt = { 1, 1, 1, 1, 1, }; 198 | +struct ipv4_devconf ipv4_devconf = { 1, 1, 1, 1, 1, 0, }; 199 | +static struct ipv4_devconf ipv4_devconf_dflt = { 1, 1, 1, 1, 1, 1, }; 200 | 201 | #ifdef CONFIG_RTNETLINK 202 | static void rtmsg_ifa(int event, struct in_ifaddr *); 203 | @@ -186,21 +186,6 @@ 204 | in_dev_put(in_dev); 205 | } 206 | 207 | -int inet_addr_onlink(struct in_device *in_dev, u32 a, u32 b) 208 | -{ 209 | - read_lock(&in_dev->lock); 210 | - for_primary_ifa(in_dev) { 211 | - if (inet_ifa_match(a, ifa)) { 212 | - if (!b || inet_ifa_match(b, ifa)) { 213 | - read_unlock(&in_dev->lock); 214 | - return 1; 215 | - } 216 | - } 217 | - } endfor_ifa(in_dev); 218 | - read_unlock(&in_dev->lock); 219 | - return 0; 220 | -} 221 | - 222 | static void 223 | inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, int destroy) 224 | { 225 | @@ -1027,7 +1012,7 @@ 226 | static struct devinet_sysctl_table 227 | { 228 | struct ctl_table_header *sysctl_header; 229 | - ctl_table devinet_vars[13]; 230 | + ctl_table devinet_vars[14]; 231 | ctl_table devinet_dev[2]; 232 | ctl_table devinet_conf_dir[2]; 233 | ctl_table devinet_proto_dir[2]; 234 | @@ -1066,6 +1051,9 @@ 235 | &proc_dointvec}, 236 | {NET_IPV4_CONF_LOG_MARTIANS, "log_martians", 237 | &ipv4_devconf.log_martians, sizeof(int), 0644, NULL, 238 | + &proc_dointvec}, 239 | + {NET_IPV4_CONF_SRC_CHECK, "source_check", 240 | + &ipv4_devconf.source_check, sizeof(int), 0644, NULL, 241 | &proc_dointvec}, 242 | {NET_IPV4_CONF_TAG, "tag", 243 | &ipv4_devconf.tag, sizeof(int), 0644, NULL, 244 | diff -ru -x*~ linux-lt-2.3.99-pre3.prev/net/ipv4/fib_frontend.c linux-lt-2.3.99-pre3/net/ipv4/fib_frontend.c 245 | --- linux-lt-2.3.99-pre3.prev/net/ipv4/fib_frontend.c Thu Dec 23 11:55:38 1999 246 | +++ linux-lt-2.3.99-pre3/net/ipv4/fib_frontend.c Tue Mar 28 19:39:50 2000 247 | @@ -30,6 +30,7 @@ 248 | #include 249 | #include 250 | #include 251 | +#include 252 | #include 253 | #include 254 | #include 255 | @@ -168,11 +169,31 @@ 256 | return dev; 257 | } 258 | 259 | +int fib_local_source(u32 saddr, u32 daddr, u8 tos, struct net_device *dev) 260 | +{ 261 | + struct rt_key key; 262 | + struct fib_result res; 263 | + 264 | + memset(&key, 0, sizeof(key)); 265 | + key.src = daddr; 266 | + key.dst = saddr; 267 | + key.tos = tos; 268 | + key.iif = dev->ifindex; 269 | + if (fib_lookup(&key, &res) == 0) { 270 | + unsigned ret; 271 | + ret = res.type; 272 | + fib_res_put(&res); 273 | + if (ret != RTN_LOCAL) 274 | + return -EINVAL; 275 | + } 276 | + return 0; 277 | +} 278 | + 279 | unsigned inet_addr_type(u32 addr) 280 | { 281 | struct rt_key key; 282 | struct fib_result res; 283 | - unsigned ret = RTN_BROADCAST; 284 | + unsigned ret; 285 | 286 | if (ZERONET(addr) || BADCLASS(addr)) 287 | return RTN_BROADCAST; 288 | @@ -180,21 +201,57 @@ 289 | return RTN_MULTICAST; 290 | 291 | memset(&key, 0, sizeof(key)); 292 | + key.src = addr; 293 | key.dst = addr; 294 | -#ifdef CONFIG_IP_MULTIPLE_TABLES 295 | - res.r = NULL; 296 | -#endif 297 | 298 | - if (local_table) { 299 | - ret = RTN_UNICAST; 300 | - if (local_table->tb_lookup(local_table, &key, &res) == 0) { 301 | - ret = res.type; 302 | - fib_res_put(&res); 303 | - } 304 | + ret = RTN_UNICAST; 305 | + if (fib_lookup(&key, &res) == 0) { 306 | + ret = res.type; 307 | + fib_res_put(&res); 308 | } 309 | return ret; 310 | } 311 | 312 | +u32 fib_select_addr(struct net_device *dev, u32 dst, int scope) 313 | +{ 314 | + struct rt_key key; 315 | + struct fib_result res; 316 | + u32 ret; 317 | + 318 | + memset(&key, 0, sizeof(key)); 319 | + key.src = dst; 320 | + key.dst = dst; 321 | + key.oif = dev->ifindex; 322 | + key.scope = scope; 323 | + 324 | + if (fib_lookup(&key, &res) == 0) { 325 | + ret = FIB_RES_PREFSRC(res); 326 | + fib_res_put(&res); 327 | + } else 328 | + ret = inet_select_addr(dev, dst, scope); 329 | + return ret; 330 | +} 331 | + 332 | +/* Check if dst is a UNICAST address and reachable via device dev */ 333 | +int inet_addr_onlink(struct net_device *dev, u32 dst, u32 src, u8 tos) 334 | +{ 335 | + struct rt_key key; 336 | + struct fib_result res; 337 | + int ret; 338 | + 339 | + key.src = src; 340 | + key.dst = dst; 341 | + key.tos = tos; 342 | + key.iif = 0; 343 | + key.oif = 0; 344 | + key.scope = RT_SCOPE_LINK; 345 | + if (fib_lookup(&key, &res) != 0) 346 | + return 0; 347 | + ret = (res.type == RTN_UNICAST && FIB_RES_DEV(res) == dev); 348 | + fib_res_put(&res); 349 | + return ret; 350 | +} 351 | + 352 | /* Given (packet source, input interface) and optional (dst, oif, tos): 353 | - (main) check, that source is valid i.e. not broadcast or our local 354 | address. 355 | @@ -559,7 +616,7 @@ 356 | First of all, we scan fib_info list searching 357 | for stray nexthop entries, then ignite fib_flush. 358 | */ 359 | - if (fib_sync_down(ifa->ifa_local, NULL, 0)) 360 | + if (fib_sync_addr_down(ifa->ifa_local)) 361 | fib_flush(); 362 | } 363 | } 364 | @@ -571,7 +628,7 @@ 365 | 366 | static void fib_disable_ip(struct net_device *dev, int force) 367 | { 368 | - if (fib_sync_down(0, dev, force)) 369 | + if (fib_sync_dev_down(dev, force)) 370 | fib_flush(); 371 | rt_cache_flush(0); 372 | arp_ifdown(dev); 373 | @@ -591,8 +648,10 @@ 374 | /* Last address was deleted from this interface. 375 | Disable IP. 376 | */ 377 | + printk("fib_inetaddr_event: dev down, fib_disable_ip(1)\n"); 378 | fib_disable_ip(ifa->ifa_dev->dev, 1); 379 | } else { 380 | + printk("fib_inetaddr_event: dev down, fib_del_ifaddr\n"); 381 | fib_del_ifaddr(ifa); 382 | rt_cache_flush(-1); 383 | } 384 | @@ -606,11 +665,10 @@ 385 | struct net_device *dev = ptr; 386 | struct in_device *in_dev = __in_dev_get(dev); 387 | 388 | - if (!in_dev) 389 | - return NOTIFY_DONE; 390 | - 391 | switch (event) { 392 | case NETDEV_UP: 393 | + if (!in_dev) 394 | + break; 395 | for_ifa(in_dev) { 396 | fib_add_ifaddr(ifa); 397 | } endfor_ifa(in_dev); 398 | @@ -620,9 +678,18 @@ 399 | rt_cache_flush(-1); 400 | break; 401 | case NETDEV_DOWN: 402 | + printk("fib_netdev_event: dev down, fib_disable_ip(0)\n"); 403 | fib_disable_ip(dev, 0); 404 | break; 405 | case NETDEV_UNREGISTER: 406 | + /* Routes pointing to dev may still exists even when IP has 407 | + * been shut down. It may happen because routes of local type 408 | + * has special nexthop (see fib_create_info() and 409 | + * fib_sync_dev_down()). I don't know if this state is valid. 410 | + * Now I call fib_disable_ip() independently from if the device 411 | + * has IP because otherwise stale device references are left. 412 | + * 1999/11/28 SAW */ 413 | + printk("fib_netdev_event: dev unregister, fib_disable_ip(1)\n"); 414 | fib_disable_ip(dev, 1); 415 | break; 416 | case NETDEV_CHANGEMTU: 417 | diff -ru -x*~ linux-lt-2.3.99-pre3.prev/net/ipv4/fib_semantics.c linux-lt-2.3.99-pre3/net/ipv4/fib_semantics.c 418 | --- linux-lt-2.3.99-pre3.prev/net/ipv4/fib_semantics.c Tue Aug 24 01:01:02 1999 419 | +++ linux-lt-2.3.99-pre3/net/ipv4/fib_semantics.c Tue Mar 28 19:39:50 2000 420 | @@ -345,14 +345,15 @@ 421 | { 422 | int err; 423 | 424 | + if (nh->nh_flags&RTNH_F_PERVASIVE) { 425 | + fi->fib_flags |= RTCF_PERVASIVE; 426 | + return 0; 427 | + } 428 | + 429 | if (nh->nh_gw) { 430 | struct rt_key key; 431 | struct fib_result res; 432 | 433 | -#ifdef CONFIG_IP_ROUTE_PERVASIVE 434 | - if (nh->nh_flags&RTNH_F_PERVASIVE) 435 | - return 0; 436 | -#endif 437 | if (nh->nh_flags&RTNH_F_ONLINK) { 438 | struct net_device *dev; 439 | 440 | @@ -389,7 +390,7 @@ 441 | } else { 442 | struct in_device *in_dev; 443 | 444 | - if (nh->nh_flags&(RTNH_F_PERVASIVE|RTNH_F_ONLINK)) 445 | + if (nh->nh_flags&RTNH_F_ONLINK) 446 | return -EINVAL; 447 | 448 | in_dev = inetdev_by_index(nh->nh_oif); 449 | @@ -528,7 +529,7 @@ 450 | } endfor_nexthops(fi) 451 | } 452 | 453 | - if (fi->fib_prefsrc) { 454 | + if (fi->fib_prefsrc && !(fi->fib_flags&RTCF_PERVASIVE)) { 455 | if (r->rtm_type != RTN_LOCAL || rta->rta_dst == NULL || 456 | memcmp(&fi->fib_prefsrc, rta->rta_dst, 4)) 457 | if (inet_addr_type(fi->fib_prefsrc) != RTN_LOCAL) 458 | @@ -857,19 +858,34 @@ 459 | - device went down -> we must shutdown all nexthops going via it. 460 | */ 461 | 462 | -int fib_sync_down(u32 local, struct net_device *dev, int force) 463 | +int fib_sync_addr_down(u32 local) 464 | +{ 465 | + int ret = 0; 466 | + 467 | + if (!local) 468 | + goto out; 469 | + 470 | + for_fib_info() { 471 | + if (fi->fib_prefsrc == local && 472 | + !(fi->fib_flags&RTCF_PERVASIVE)) { 473 | + fi->fib_flags |= RTCF_DEAD; 474 | + ret++; 475 | + } 476 | + } endfor_fib_info(); 477 | +out: 478 | + return ret; 479 | +} 480 | + 481 | +int fib_sync_dev_down(struct net_device *dev, int force) 482 | { 483 | int ret = 0; 484 | int scope = RT_SCOPE_NOWHERE; 485 | - 486 | + 487 | if (force) 488 | scope = -1; 489 | 490 | for_fib_info() { 491 | - if (local && fi->fib_prefsrc == local) { 492 | - fi->fib_flags |= RTNH_F_DEAD; 493 | - ret++; 494 | - } else if (dev && fi->fib_nhs) { 495 | + if (fi->fib_nhs) { 496 | int dead = 0; 497 | 498 | change_nexthops(fi) { 499 | @@ -886,7 +902,7 @@ 500 | } 501 | } endfor_nexthops(fi) 502 | if (dead == fi->fib_nhs) { 503 | - fi->fib_flags |= RTNH_F_DEAD; 504 | + fi->fib_flags |= RTCF_DEAD; 505 | ret++; 506 | } 507 | } 508 | @@ -947,6 +963,10 @@ 509 | int power = 0; 510 | change_nexthops(fi) { 511 | if (!(nh->nh_flags&RTNH_F_DEAD)) { 512 | + if (nh->nh_flags&RTNH_F_USEFIRST) { 513 | + res->nh_sel = nhsel; 514 | + return; 515 | + } 516 | power += nh->nh_weight; 517 | nh->nh_power = nh->nh_weight; 518 | } 519 | diff -ru -x*~ linux-lt-2.3.99-pre3.prev/net/ipv4/route.c linux-lt-2.3.99-pre3/net/ipv4/route.c 520 | --- linux-lt-2.3.99-pre3.prev/net/ipv4/route.c Mon Mar 27 18:25:56 2000 521 | +++ linux-lt-2.3.99-pre3/net/ipv4/route.c Tue Mar 28 19:57:19 2000 522 | @@ -711,22 +711,28 @@ 523 | struct rtable *rth, **rthp; 524 | u32 skeys[2] = { saddr, 0 }; 525 | int ikeys[2] = { dev->ifindex, 0 }; 526 | + char *reason; 527 | 528 | tos &= IPTOS_TOS_MASK; 529 | 530 | if (!in_dev) 531 | return; 532 | 533 | + reason = "bad gateway"; 534 | if (new_gw == old_gw || !IN_DEV_RX_REDIRECTS(in_dev) 535 | || MULTICAST(new_gw) || BADCLASS(new_gw) || ZERONET(new_gw)) 536 | goto reject_redirect; 537 | 538 | if (!IN_DEV_SHARED_MEDIA(in_dev)) { 539 | - if (!inet_addr_onlink(in_dev, new_gw, old_gw)) 540 | + reason = "gateway not onlink"; 541 | + if (!inet_addr_onlink(dev, new_gw, saddr, tos)) 542 | goto reject_redirect; 543 | - if (IN_DEV_SEC_REDIRECTS(in_dev) && ip_fib_check_default(new_gw, dev)) 544 | + reason = "insecure gateway"; 545 | + if (IN_DEV_SEC_REDIRECTS(in_dev) && 546 | + ip_fib_check_default(new_gw, dev)) 547 | goto reject_redirect; 548 | } else { 549 | + reason = "unacceptable gateway"; 550 | if (inet_addr_type(new_gw) != RTN_UNICAST) 551 | goto reject_redirect; 552 | } 553 | @@ -816,9 +822,9 @@ 554 | reject_redirect: 555 | #ifdef CONFIG_IP_ROUTE_VERBOSE 556 | if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit()) 557 | - printk(KERN_INFO "Redirect from %X/%s to %X ignored." 558 | + printk(KERN_INFO "Redirect from %X/%s to %X ignored (%s). " 559 | "Path = %X -> %X, tos %02x\n", 560 | - ntohl(old_gw), dev->name, ntohl(new_gw), 561 | + ntohl(old_gw), dev->name, ntohl(new_gw), reason, 562 | ntohl(saddr), ntohl(daddr), tos); 563 | #endif 564 | in_dev_put(in_dev); 565 | @@ -836,7 +842,7 @@ 566 | if ((rt->rt_flags&RTCF_REDIRECTED) || rt->u.dst.expires) { 567 | unsigned hash = rt_hash_code(rt->key.dst, rt->key.src^(rt->key.oif<<5), rt->key.tos); 568 | #if RT_CACHE_DEBUG >= 1 569 | - printk(KERN_DEBUG "ip_rt_advice: redirect to %d.%d.%d.%d/%02x dropped\n", NIPQUAD(rt->rt_dst), rt->key.tos); 570 | + printk(KERN_DEBUG "ip_rt_advice: cache entry to %d.%d.%d.%d/%02x dropped\n", NIPQUAD(rt->rt_dst), rt->key.tos); 571 | #endif 572 | rt_del(hash, rt); 573 | return NULL; 574 | @@ -1106,6 +1112,10 @@ 575 | } 576 | #endif 577 | 578 | +/********************************************************************* 579 | + Input/output routing 580 | + *********************************************************************/ 581 | + 582 | static void rt_set_nexthop(struct rtable *rt, struct fib_result *res, u32 itag) 583 | { 584 | struct fib_info *fi = res->fi; 585 | @@ -1145,6 +1155,10 @@ 586 | rt->rt_type = res->type; 587 | } 588 | 589 | +/********************************************************************* 590 | + Input 591 | + *********************************************************************/ 592 | + 593 | static int 594 | ip_route_input_mc(struct sk_buff *skb, u32 daddr, u32 saddr, 595 | u8 tos, struct net_device *dev, int our) 596 | @@ -1362,9 +1376,7 @@ 597 | if (err) 598 | flags |= RTCF_DIRECTSRC; 599 | 600 | - if (out_dev == in_dev && err && !(flags&(RTCF_NAT|RTCF_MASQ)) && 601 | - (IN_DEV_SHARED_MEDIA(out_dev) 602 | - || inet_addr_onlink(out_dev, saddr, FIB_RES_GW(res)))) 603 | + if (out_dev == in_dev && err && !(flags&(RTCF_NAT|RTCF_MASQ))) 604 | flags |= RTCF_DOREDIRECT; 605 | 606 | if (skb->protocol != __constant_htons(ETH_P_IP)) { 607 | @@ -1592,22 +1604,183 @@ 608 | return ip_route_input_slow(skb, daddr, saddr, tos, dev); 609 | } 610 | 611 | +/********************************************************************* 612 | + Output 613 | + *********************************************************************/ 614 | + 615 | +/* TODO: 616 | + - Check if CONFIG_IP_MROUTE ifdef makes any sense. 617 | + */ 618 | + 619 | +/* User supplied source address verification for output packets. 620 | + Such a verification can't be considered as a security measure. 621 | + It's rather an additional Internet protection against bugs in applications 622 | + (like using an uninitialized garbage as a source for UDP packets). 623 | + */ 624 | +static int outrt_check_src(u32 saddr, u32 daddr, u32 tos, struct net_device *dev_out) 625 | +{ 626 | + struct in_device *in_dev; 627 | + int src_check; 628 | + 629 | + if (MULTICAST(saddr) || BADCLASS(saddr) || ZERONET(saddr)) 630 | + return -EINVAL; 631 | + if (saddr == htonl(INADDR_BROADCAST)) 632 | + return -EINVAL; 633 | + 634 | + in_dev = in_dev_get(dev_out); 635 | + src_check = IN_DEV_SRC_CHECK(in_dev); 636 | + in_dev_put(in_dev); 637 | + if (!src_check) 638 | + return 0; 639 | + 640 | + if (LOOPBACK(saddr) && !(dev_out->flags&IFF_LOOPBACK)) 641 | + return -EINVAL; 642 | + 643 | + return fib_local_source(saddr, daddr, tos, dev_out); 644 | +} 645 | + 646 | +static int outrt_make_route(struct rtable **rp, 647 | + /* route lookup key */ 648 | + struct rt_key *key, 649 | + /* path */ 650 | + u32 daddr, u32 saddr, struct net_device *dev_out, 651 | + /* FIB lookup results (type, fi, nh.gw, nh.scope) */ 652 | + struct fib_result *res 653 | + ) 654 | +{ 655 | + struct rtable *rth; 656 | + unsigned hash; 657 | + unsigned flags; 658 | + 659 | + rth = dst_alloc(&ipv4_dst_ops); 660 | + if (!rth) 661 | + return -ENOBUFS; 662 | + 663 | + atomic_set(&rth->u.dst.__refcnt, 1); 664 | + rth->u.dst.flags= DST_HOST; 665 | + rth->key = *key; 666 | + rth->key.iif = 0; /* output route */ 667 | + rth->rt_dst = daddr; 668 | + rth->rt_src = saddr; 669 | +#ifdef CONFIG_IP_ROUTE_NAT 670 | + rth->rt_dst_map = daddr; 671 | + rth->rt_src_map = saddr; 672 | +#endif 673 | + 674 | + /* Set input, output ROUTINES and rt_spec_dst */ 675 | + switch (res->type) { 676 | + case RTN_LOCAL: 677 | + /* Use loopback interface for unicast local traffic */ 678 | + fib_res_put(res); 679 | + res->fi = NULL; 680 | +#ifdef CONFIG_IP_MULTIPLE_TABLES 681 | + res->r = NULL; 682 | +#endif 683 | + dev_out = &loopback_dev; 684 | + flags = RTCF_LOCAL; 685 | + rth->u.dst.input = ip_local_deliver; 686 | + rth->u.dst.output = ip_output; 687 | + rth->rt_spec_dst = daddr; /* local side of the path */ 688 | + break; 689 | + case RTN_UNICAST: 690 | + flags = 0; 691 | + rth->u.dst.output = ip_output; 692 | + rth->rt_spec_dst = saddr; 693 | +#ifdef CONFIG_IP_ROUTE_MULTIPATH 694 | + if (res->fi->fib_nhs > 1 && key->oif == 0) 695 | + /* Set the proper res->nh_sel. */ 696 | + fib_select_multipath(key, res); 697 | + else 698 | +#endif 699 | + if (res->prefixlen == 0 && res->type == RTN_UNICAST && 700 | + key->oif == 0) 701 | + fib_select_default(key, res); 702 | + break; 703 | + case RTN_BROADCAST: 704 | + flags = RTCF_BROADCAST|RTCF_LOCAL; 705 | + rth->u.dst.input = ip_local_deliver; 706 | + if (!(dev_out->flags&IFF_LOOPBACK)) 707 | + rth->u.dst.output = ip_mc_output; 708 | + else 709 | + rth->u.dst.output = ip_output; 710 | + rth->rt_spec_dst = saddr; 711 | + break; 712 | + case RTN_MULTICAST: 713 | + { 714 | + /* Please note that all ancient band-aids were removed. 715 | + I don't try to catch route table deficient for 716 | + multicast or 255.255.255.255 routes and "smartly" 717 | + replace a gatewayed default by the corresponding 718 | + route. 1999/11/06 SAW 719 | + */ 720 | + struct in_device *in_dev = in_dev_get(dev_out); 721 | + rth->u.dst.input = ip_local_deliver; 722 | + rth->u.dst.output = ip_output; 723 | + flags = RTCF_MULTICAST; 724 | + if (in_dev && ip_check_mc(in_dev, daddr)) { 725 | + /* Note: I preserve the original behaviour 726 | + here. It means that users after joining and 727 | + leaving a multicast group have to flush 728 | + the route cache. I hope they know about it 729 | + :-) 1999/11/06 SAW 730 | + */ 731 | + flags = RTCF_MULTICAST|RTCF_LOCAL; 732 | + if (!(dev_out->flags&IFF_LOOPBACK)) 733 | + rth->u.dst.output = ip_mc_output; 734 | + } 735 | +#ifdef CONFIG_IP_MROUTE 736 | + if (in_dev && !(dev_out->flags&IFF_LOOPBACK)) { 737 | + if (IN_DEV_MFORWARD(in_dev) && 738 | + !LOCAL_MCAST(daddr)) 739 | + { 740 | + rth->u.dst.input = ip_mr_input; 741 | + rth->u.dst.output = ip_mc_output; 742 | + } 743 | + } 744 | +#endif 745 | + if (in_dev) 746 | + in_dev_put(in_dev); 747 | + rth->rt_spec_dst = saddr; 748 | + } 749 | + break; 750 | + case RTN_NAT: 751 | + dst_free(&rth->u.dst); 752 | + return -EINVAL; 753 | + default: 754 | + printk(KERN_CRIT "bad lookup result type in route output\n"); 755 | + return -EINVAL; 756 | + } 757 | + 758 | + /* INTERFACE */ 759 | + /* Store the interface information to allow users to get it via 760 | + * [SOL_IP, IP_PKTINFO] conrol message for locally seen packets 761 | + * (including broadcast and multicast ones). --SAW */ 762 | + rth->rt_iif = key->oif ? : dev_out->ifindex; 763 | + /* Set output device */ 764 | + rth->u.dst.dev = dev_out; 765 | + dev_hold(dev_out); 766 | + 767 | + /* Set GATEWAY */ 768 | + rth->rt_gateway = daddr; 769 | + /* if res->fi != NULL set the real gateway */ 770 | + rt_set_nexthop(rth, res, 0); 771 | + 772 | + rth->rt_flags = flags; 773 | + 774 | + hash = rt_hash_code(key->dst, key->src^(key->oif<<5), key->tos); 775 | + return rt_intern_hash(hash, rth, rp); 776 | +} 777 | + 778 | /* 779 | * Major route resolver routine. 780 | */ 781 | - 782 | int ip_route_output_slow(struct rtable **rp, u32 daddr, u32 saddr, u32 tos, int oif) 783 | { 784 | struct rt_key key; 785 | struct fib_result res; 786 | - unsigned flags = 0; 787 | - struct rtable *rth; 788 | struct net_device *dev_out = NULL; 789 | - unsigned hash; 790 | - int free_res = 0; 791 | int err; 792 | 793 | - tos &= IPTOS_TOS_MASK|RTO_ONLINK; 794 | key.dst = daddr; 795 | key.src = saddr; 796 | key.tos = tos&IPTOS_TOS_MASK; 797 | @@ -1619,252 +1792,100 @@ 798 | res.r = NULL; 799 | #endif 800 | 801 | - if (saddr) { 802 | - if (MULTICAST(saddr) || BADCLASS(saddr) || ZERONET(saddr)) 803 | - return -EINVAL; 804 | - 805 | - /* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */ 806 | - dev_out = ip_dev_find(saddr); 807 | - if (dev_out == NULL) 808 | - return -EINVAL; 809 | - 810 | - /* I removed check for oif == dev_out->oif here. 811 | - It was wrong by three reasons: 812 | - 1. ip_dev_find(saddr) can return wrong iface, if saddr is 813 | - assigned to multiple interfaces. 814 | - 2. Moreover, we are allowed to send packets with saddr 815 | - of another iface. --ANK 816 | - */ 817 | - 818 | - if (oif == 0 && 819 | - (MULTICAST(daddr) || daddr == 0xFFFFFFFF)) { 820 | - /* Special hack: user can direct multicasts 821 | - and limited broadcast via necessary interface 822 | - without fiddling with IP_MULTICAST_IF or IP_PKTINFO. 823 | - This hack is not just for fun, it allows 824 | - vic,vat and friends to work. 825 | - They bind socket to loopback, set ttl to zero 826 | - and expect that it will work. 827 | - From the viewpoint of routing cache they are broken, 828 | - because we are not allowed to build multicast path 829 | - with loopback source addr (look, routing cache 830 | - cannot know, that ttl is zero, so that packet 831 | - will not leave this host and route is valid). 832 | - Luckily, this hack is good workaround. 833 | - */ 834 | - 835 | - key.oif = dev_out->ifindex; 836 | - goto make_route; 837 | - } 838 | - if (dev_out) 839 | - dev_put(dev_out); 840 | - dev_out = NULL; 841 | - } 842 | - if (oif) { 843 | - dev_out = dev_get_by_index(oif); 844 | - if (dev_out == NULL) 845 | - return -ENODEV; 846 | - if (__in_dev_get(dev_out) == NULL) { 847 | - dev_put(dev_out); 848 | - return -ENODEV; /* Wrong error code */ 849 | - } 850 | - 851 | - if (LOCAL_MCAST(daddr) || daddr == 0xFFFFFFFF) { 852 | - if (!key.src) 853 | - key.src = inet_select_addr(dev_out, 0, RT_SCOPE_LINK); 854 | - goto make_route; 855 | - } 856 | - if (!key.src) { 857 | - if (MULTICAST(daddr)) 858 | - key.src = inet_select_addr(dev_out, 0, key.scope); 859 | - else if (!daddr) 860 | - key.src = inet_select_addr(dev_out, 0, RT_SCOPE_HOST); 861 | - } 862 | - } 863 | + if (!daddr) 864 | + goto dest_insanity; 865 | 866 | - if (!key.dst) { 867 | - key.dst = key.src; 868 | - if (!key.dst) 869 | - key.dst = key.src = htonl(INADDR_LOOPBACK); 870 | - if (dev_out) 871 | - dev_put(dev_out); 872 | - dev_out = &loopback_dev; 873 | + err = fib_lookup(&key, &res); 874 | + if (!err) { 875 | + dev_out = FIB_RES_DEV(res); 876 | dev_hold(dev_out); 877 | - key.oif = loopback_dev.ifindex; 878 | - res.type = RTN_LOCAL; 879 | - flags |= RTCF_LOCAL; 880 | - goto make_route; 881 | - } 882 | - 883 | - if (fib_lookup(&key, &res)) { 884 | - res.fi = NULL; 885 | - if (oif) { 886 | - /* Apparently, routing tables are wrong. Assume, 887 | - that the destination is on link. 888 | - 889 | - WHY? DW. 890 | - Because we are allowed to send to iface 891 | - even if it has NO routes and NO assigned 892 | - addresses. When oif is specified, routing 893 | - tables are looked up with only one purpose: 894 | - to catch if destination is gatewayed, rather than 895 | - direct. Moreover, if MSG_DONTROUTE is set, 896 | - we send packet, ignoring both routing tables 897 | - and ifaddr state. --ANK 898 | - 899 | - 900 | - We could make it even if oif is unknown, 901 | - likely IPv6, but we do not. 902 | + if (saddr) { 903 | + /* Verify user supplied source address */ 904 | + err = outrt_check_src(saddr, daddr, tos, dev_out); 905 | + } else { 906 | + /* Obtain path source from routing table */ 907 | + saddr = FIB_RES_PREFSRC(res); 908 | + /* We don't verify source address obtained from routing 909 | + * table. It's a task of administrators to keep it 910 | + * sane. 911 | */ 912 | - 913 | - if (key.src == 0) 914 | - key.src = inet_select_addr(dev_out, 0, RT_SCOPE_LINK); 915 | - res.type = RTN_UNICAST; 916 | - goto make_route; 917 | } 918 | - if (dev_out) 919 | - dev_put(dev_out); 920 | - return -ENETUNREACH; 921 | - } 922 | - free_res = 1; 923 | - 924 | - if (res.type == RTN_NAT) 925 | - goto e_inval; 926 | - 927 | - if (res.type == RTN_LOCAL) { 928 | - if (!key.src) 929 | - key.src = key.dst; 930 | - if (dev_out) 931 | - dev_put(dev_out); 932 | - dev_out = &loopback_dev; 933 | - dev_hold(dev_out); 934 | - key.oif = dev_out->ifindex; 935 | - if (res.fi) 936 | - fib_info_put(res.fi); 937 | - res.fi = NULL; 938 | - flags |= RTCF_LOCAL; 939 | - goto make_route; 940 | - } 941 | - 942 | -#ifdef CONFIG_IP_ROUTE_MULTIPATH 943 | - if (res.fi->fib_nhs > 1 && key.oif == 0) 944 | - fib_select_multipath(&key, &res); 945 | - else 946 | -#endif 947 | - if (res.prefixlen==0 && res.type == RTN_UNICAST && key.oif == 0) 948 | - fib_select_default(&key, &res); 949 | - 950 | - if (!key.src) 951 | - key.src = FIB_RES_PREFSRC(res); 952 | - 953 | - if (dev_out) 954 | - dev_put(dev_out); 955 | - dev_out = FIB_RES_DEV(res); 956 | - dev_hold(dev_out); 957 | - key.oif = dev_out->ifindex; 958 | - 959 | -make_route: 960 | - if (LOOPBACK(key.src) && !(dev_out->flags&IFF_LOOPBACK)) 961 | - goto e_inval; 962 | - 963 | - if (key.dst == 0xFFFFFFFF) 964 | - res.type = RTN_BROADCAST; 965 | - else if (MULTICAST(key.dst)) 966 | - res.type = RTN_MULTICAST; 967 | - else if (BADCLASS(key.dst) || ZERONET(key.dst)) 968 | - goto e_inval; 969 | + if (!err) 970 | + err = outrt_make_route(rp, &key, daddr, saddr, 971 | + dev_out, &res); 972 | + fib_res_put(&res); 973 | + /* The usual code path ends here */ 974 | 975 | - if (dev_out->flags&IFF_LOOPBACK) 976 | - flags |= RTCF_LOCAL; 977 | + } else if (err == -ENETUNREACH) { 978 | 979 | - if (res.type == RTN_BROADCAST) { 980 | - flags |= RTCF_BROADCAST|RTCF_LOCAL; 981 | - if (res.fi) { 982 | - fib_info_put(res.fi); 983 | - res.fi = NULL; 984 | - } 985 | - } else if (res.type == RTN_MULTICAST) { 986 | - flags |= RTCF_MULTICAST|RTCF_LOCAL; 987 | - read_lock(&inetdev_lock); 988 | - if (!__in_dev_get(dev_out) || !ip_check_mc(__in_dev_get(dev_out), daddr)) 989 | - flags &= ~RTCF_LOCAL; 990 | - read_unlock(&inetdev_lock); 991 | - /* If multicast route do not exist use 992 | - default one, but do not gateway in this case. 993 | - Yes, it is hack. 994 | + /* Just return if the access is prohibited etc. 995 | + If the routing table doesn't have both an appropriate route 996 | + and a default assume that the destination is on link. --SAW 997 | + 998 | + WHY? DW. 999 | + Because we are allowed to send to iface 1000 | + even if it has NO routes and NO assigned 1001 | + addresses. When oif is specified, routing 1002 | + tables are looked up with only one purpose: 1003 | + to catch if destination is gatewayed, rather than 1004 | + direct. Moreover, if MSG_DONTROUTE is set, 1005 | + we send packet, ignoring both routing tables 1006 | + and ifaddr state. --ANK 1007 | + 1008 | + We could make it even if oif is unknown, 1009 | + likely IPv6, but we do not. 1010 | + 1011 | + The above statements aren't exactly correct. 1012 | + Routing tables contain a lot of useful information (like 1013 | + preferred source, for instance). But the general idea is 1014 | + right. --SAW 1015 | */ 1016 | - if (res.fi && res.prefixlen < 4) { 1017 | - fib_info_put(res.fi); 1018 | - res.fi = NULL; 1019 | - } 1020 | - } 1021 | - 1022 | - rth = dst_alloc(&ipv4_dst_ops); 1023 | - if (!rth) 1024 | - goto e_nobufs; 1025 | - 1026 | - atomic_set(&rth->u.dst.__refcnt, 1); 1027 | - rth->u.dst.flags= DST_HOST; 1028 | - rth->key.dst = daddr; 1029 | - rth->key.tos = tos; 1030 | - rth->key.src = saddr; 1031 | - rth->key.iif = 0; 1032 | - rth->key.oif = oif; 1033 | - rth->rt_dst = key.dst; 1034 | - rth->rt_src = key.src; 1035 | -#ifdef CONFIG_IP_ROUTE_NAT 1036 | - rth->rt_dst_map = key.dst; 1037 | - rth->rt_src_map = key.src; 1038 | -#endif 1039 | - rth->rt_iif = oif ? : dev_out->ifindex; 1040 | - rth->u.dst.dev = dev_out; 1041 | - dev_hold(dev_out); 1042 | - rth->rt_gateway = key.dst; 1043 | - rth->rt_spec_dst= key.src; 1044 | - 1045 | - rth->u.dst.output=ip_output; 1046 | - 1047 | - if (flags&RTCF_LOCAL) { 1048 | - rth->u.dst.input = ip_local_deliver; 1049 | - rth->rt_spec_dst = key.dst; 1050 | - } 1051 | - if (flags&(RTCF_BROADCAST|RTCF_MULTICAST)) { 1052 | - rth->rt_spec_dst = key.src; 1053 | - if (flags&RTCF_LOCAL && !(dev_out->flags&IFF_LOOPBACK)) 1054 | - rth->u.dst.output = ip_mc_output; 1055 | -#ifdef CONFIG_IP_MROUTE 1056 | - if (res.type == RTN_MULTICAST) { 1057 | - struct in_device *in_dev = in_dev_get(dev_out); 1058 | - if (in_dev) { 1059 | - if (IN_DEV_MFORWARD(in_dev) && !LOCAL_MCAST(daddr)) { 1060 | - rth->u.dst.input = ip_mr_input; 1061 | - rth->u.dst.output = ip_mc_output; 1062 | - } 1063 | - in_dev_put(in_dev); 1064 | + if (oif) { 1065 | + err = -ENODEV; 1066 | + dev_out = dev_get_by_index(oif); 1067 | + if (dev_out == NULL) 1068 | + goto out; 1069 | + if (__in_dev_get(dev_out) == NULL) 1070 | + goto out; /* Wrong error code */ 1071 | + if (saddr) { 1072 | + /* Verify user supplied source address */ 1073 | + err = outrt_check_src(saddr, daddr, tos, dev_out); 1074 | + if (err) 1075 | + goto out; 1076 | + } else { 1077 | + int scope; 1078 | + if (LOCAL_MCAST(daddr) || daddr == 0xFFFFFFFF) 1079 | + scope = RT_SCOPE_LINK; 1080 | + else if (MULTICAST(daddr)) 1081 | + scope = key.scope; 1082 | + else 1083 | + scope = RT_SCOPE_HOST; 1084 | + saddr = inet_select_addr(dev_out, 0, scope); 1085 | } 1086 | - } 1087 | -#endif 1088 | + res.type = RTN_UNICAST; 1089 | + res.fi = NULL; 1090 | + err = outrt_make_route(rp, &key, daddr, saddr, dev_out, 1091 | + &res); 1092 | + } else 1093 | + err = -ENETUNREACH; 1094 | } 1095 | - 1096 | - rt_set_nexthop(rth, &res, 0); 1097 | - 1098 | - rth->rt_flags = flags; 1099 | - 1100 | - hash = rt_hash_code(daddr, saddr^(oif<<5), tos); 1101 | - err = rt_intern_hash(hash, rth, rp); 1102 | -done: 1103 | - if (free_res) 1104 | - fib_res_put(&res); 1105 | +out: 1106 | if (dev_out) 1107 | dev_put(dev_out); 1108 | return err; 1109 | 1110 | -e_inval: 1111 | - err = -EINVAL; 1112 | - goto done; 1113 | -e_nobufs: 1114 | - err = -ENOBUFS; 1115 | - goto done; 1116 | + /* I don't know what reason this hack was for */ 1117 | +dest_insanity: 1118 | + daddr = saddr; 1119 | + if (!daddr) 1120 | + daddr = saddr = htonl(INADDR_LOOPBACK); 1121 | + dev_out = &loopback_dev; 1122 | + dev_hold(dev_out); 1123 | + key.oif = loopback_dev.ifindex; 1124 | + res.type = RTN_LOCAL; 1125 | + res.fi = NULL; 1126 | + err = outrt_make_route(rp, &key, daddr, saddr, dev_out, &res); 1127 | + goto out; 1128 | } 1129 | 1130 | int ip_route_output(struct rtable **rp, u32 daddr, u32 saddr, u32 tos, int oif) 1131 | -------------------------------------------------------------------------------- /scott_example: -------------------------------------------------------------------------------- 1 | vrrpd -i eth0 -v 1 -n 12.12.199.1 172.16.117.150 2 | -------------------------------------------------------------------------------- /vrrpd.8: -------------------------------------------------------------------------------- 1 | .\" -*- nroff -*- 2 | .TH VRRPD 8 "September 2000" "vrrpd(8)" "Vrrpd's Manual" 3 | .SH NAME 4 | vrrpd \- Virtual Router Redundancy Protocol Deamon 5 | .SH SYNOPSIS 6 | .B vrrpd 7 | -i ifname -v vrid [-s] [-a auth] [-p prio] [-nh] ipaddr 8 | .SH DESCRIPTION 9 | vrrpd is an implementation of VRRPv2 as specified in rfc2338. It run 10 | in userspace for linux. 11 | In short, VRRP is a protocol which elects a master server on a LAN and 12 | the master answers to a 'virtual ip address'. If it fails, a backup 13 | server takes over the ip address. 14 | 15 | A longuer answer in the rfc2338 abstract : 16 | "This memo defines the Virtual Router Redundancy Protocol (VRRP). 17 | VRRP specifies an election protocol that dynamically assigns 18 | responsibility for a virtual router to one of the VRRP routers on a 19 | LAN. The VRRP router controlling the IP address(es) associated with 20 | a virtual router is called the Master, and forwards packets sent to 21 | these IP addresses. The election process provides dynamic fail over 22 | in the forwarding responsibility should the Master become 23 | unavailable. This allows any of the virtual router IP addresses on 24 | the LAN to be used as the default first hop router by end-hosts. The 25 | advantage gained from using VRRP is a higher availability default 26 | path without requiring configuration of dynamic routing or router 27 | discovery protocols on every end-host." 28 | Copyright (C) The Internet Society (1998). All Rights Reserved. 29 | 30 | 31 | .SS OPTIONS 32 | .TP 33 | .I "-h" 34 | display this short inlined help 35 | .TP 36 | .I "-n" 37 | Dont handle the virtual mac address 38 | .TP 39 | .I "-i ifname" 40 | the interface name to run on 41 | .TP 42 | .I "-v vrid" 43 | the id of the virtual server [1-255] 44 | .TP 45 | .I "-s" 46 | Switch the preemption mode (Enabled by default) 47 | .TP 48 | .I "-a auth" 49 | (not yet implemented) set the authentification type 50 | auth=(none|pw/hexkey|ah/hexkey) hexkey=0x[0-9a-fA-F]+ 51 | Password is a symbolic security, anybody with a sniffer can break it. 52 | AH is a bit stronger but not yet implemented. 53 | .TP 54 | .I "-p prio" 55 | Set the priority of this host in the virtual server (dfl: 100) 56 | .TP 57 | .I "-f piddir" 58 | specify the directory where the pid file is stored (dfl: /var/run) 59 | .TP 60 | .I "-d delay" 61 | Set the advertisement interval (in sec) (dfl: 1) 62 | .TP 63 | .I "ipaddr" 64 | the ip address(es) of the virtual server 65 | 66 | .SH EXAMPLES 67 | vrrpd -i eth0 -v 50 10.0.0.1 68 | 69 | run vrrp on the interface eth0 with the virtual id 50 and 10.0.0.1 as virtual 70 | ip address 71 | 72 | .SH AUTHOR 73 | .B vrrpd 74 | was written by Jerome Etienne 75 | .SH BUGS 76 | If you find bugs, tell me. 77 | 78 | -------------------------------------------------------------------------------- /vrrpd.h: -------------------------------------------------------------------------------- 1 | /*==========================[ (c) GURU SOFT ]=================================== 2 | FILE : [vrrp.h] 3 | CREATED : 00/02/02 12:12:06 LAST SAVE : 00/10/04 21:59:46 4 | WHO : jerome@mycpu Linux 2.2.14 5 | REMARK : 6 | ================================================================================ 7 | - This program is free software; you can redistribute it and/or 8 | modify it under the terms of the GNU General Public License 9 | as published by the Free Software Foundation; either version 10 | 2 of the License, or (at your option) any later version. 11 | ==============================================================================*/ 12 | 13 | #ifndef __VRRP_H__ 14 | #define __VRRP_H__ 15 | 16 | /* system include */ 17 | #include 18 | 19 | #define VRRPD_VERSION "Advanced Vrrpd 1.15" 20 | /* Scott added 9-4-02 */ 21 | #include 22 | #define vrrpd_log syslog 23 | 24 | /* local include */ 25 | 26 | typedef struct { /* rfc2338.5.1 */ 27 | uint8_t vers_type; /* 0-3=type, 4-7=version */ 28 | uint8_t vrid; /* virtual router id */ 29 | uint8_t priority; /* router priority */ 30 | uint8_t naddr; /* address counter */ 31 | uint8_t auth_type; /* authentification type */ 32 | uint8_t adver_int; /* advertissement interval(in sec) */ 33 | uint16_t chksum; /* checksum (ip-like one) */ 34 | /* here ip addresses */ 35 | /* here authentification infos */ 36 | } vrrp_pkt; 37 | 38 | /* protocol constants */ 39 | #define INADDR_VRRP_GROUP 0xe0000012 /* multicast addr - rfc2338.5.2.2 */ 40 | #define VRRP_IP_TTL 255 /* in and out pkt ttl -- rfc2338.5.2.3 */ 41 | #define IPPROTO_VRRP 112 /* IP protocol number -- rfc2338.5.2.4*/ 42 | #define VRRP_VERSION 2 /* current version -- rfc2338.5.3.1 */ 43 | #define VRRP_PKT_ADVERT 1 /* packet type -- rfc2338.5.3.2 */ 44 | #define VRRP_PRIO_OWNER 255 /* priority of the ip owner -- rfc2338.5.3.4 */ 45 | #define VRRP_PRIO_DFL 100 /* default priority -- rfc2338.5.3.4 */ 46 | #define VRRP_PRIO_STOP 0 /* priority to stop -- rfc2338.5.3.4 */ 47 | #define VRRP_AUTH_NONE 0 /* no authentification -- rfc2338.5.3.6 */ 48 | #define VRRP_AUTH_PASS 1 /* password authentification -- rfc2338.5.3.6 */ 49 | #define VRRP_AUTH_AH 2 /* AH(IPSec) authentification - rfc2338.5.3.6 */ 50 | #define VRRP_ADVER_DFL 2 /* advert. interval (in sec) -- rfc2338.5.3.7 */ 51 | #define VRRP_PREEMPT_DFL 1 /* rfc2338.6.1.2.Preempt_Mode */ 52 | 53 | /* implementation specific */ 54 | #define VRRP_PIDDIR_DFL "/var/run" /* dir to store the pid file */ 55 | #define VRRP_PID_FORMAT "vrrpd_%s.pid" /* pid file format */ 56 | #define ETHTOOL_GLINK 0x0000000a /* Get link status (ethtool_value) */ 57 | 58 | typedef struct { /* parameters per interface -- rfc2338.6.1.1 */ 59 | int auth_type; /* authentification type. VRRP_AUTH_* */ 60 | uint8_t auth_data[8]; /* authentification data */ 61 | 62 | uint32_t ipaddr; /* the address of the interface */ 63 | char hwaddr[6]; /* WORK: lame hardcoded for ethernet !!!! */ 64 | char *ifname; /* the device name for this ipaddr */ 65 | } vrrp_if; 66 | 67 | typedef struct { 68 | uint32_t addr; /* the ip address */ 69 | uint8_t length; /* the ip prefix length */ 70 | int deletable; /* TRUE if one of my primary addr */ 71 | } vip_addr; 72 | 73 | typedef struct { /* parameters per virtual router -- rfc2338.6.1.2 */ 74 | int vrid; /* virtual id. from 1(!) to 255 */ 75 | int priority; /* priority value */ 76 | int naddr; /* number of ip addresses */ 77 | vip_addr *vaddr; /* point on the ip address array */ 78 | int adver_int; /* delay between advertisements(in sec) */ 79 | 80 | #if 0 /* dynamically calculated */ 81 | double skew_time; /* skew Master_Down_Interval. (256-Prio)/256 */ 82 | int mast_down_int; /* interval for backup to declare master down*/ 83 | #endif 84 | int preempt; /* true if a higher prio preempt a lower one */ 85 | 86 | int state; /* internal state (init/backup/master) */ 87 | int wantstate; /* user explicitly wants a state (back/mast) */ 88 | 89 | int sockfd; /* the socket descriptor */ 90 | 91 | int initF; /* true if the struct is init */ 92 | 93 | int no_vmac; /* dont handle the virtual MAC --rfc2338.7.3 */ 94 | 95 | /* rfc2336.6.2 */ 96 | uint32_t ms_down_timer; 97 | uint32_t adver_timer; 98 | 99 | vrrp_if vif; 100 | 101 | 102 | int ttin_priority; /* priority value after SIGTTIN */ 103 | int ttou_priority; /* priority value after SIGTTOU */ 104 | 105 | } vrrp_rt; 106 | 107 | /* VRRP state machine -- rfc2338.6.4 */ 108 | #define VRRP_STATE_INIT 1 /* rfc2338.6.4.1 */ 109 | #define VRRP_STATE_BACK 2 /* rfc2338.6.4.2 */ 110 | #define VRRP_STATE_MAST 3 /* rfc2338.6.4.3 */ 111 | #define VRRP_STATE_NONE 99 /* internal */ 112 | 113 | #define VRRP_LOG( str ) printf str 114 | #define VRRP_AUTH_LEN 8 115 | 116 | #define VRRP_IS_BAD_VID(id) ((id)<1 || (id)>255) /* rfc2338.6.1.vrid */ 117 | #define VRRP_IS_BAD_PRIORITY(p) ((p)<1 || (p)>255) /* rfc2338.6.1.prio */ 118 | #define VRRP_IS_BAD_ADVERT_INT(d) ((d)<1) 119 | 120 | 121 | 122 | /* use the 'tcp sequence number arithmetic' to handle the wraparound. 123 | ** VRRP_TIMER_SUB: <0 if t1 precedes t2, =0 if t1 equals t2, >0 if t1 follows t2 124 | */ 125 | #define VRRP_TIMER_SET( val, delta ) (val) = VRRP_TIMER_CLK() + (delta) 126 | #define VRRP_TIMER_SUB( t1, t2 ) ((int32_t)(((uint32_t)t1)-((uint32_t)t2))) 127 | #define VRRP_TIMER_DELTA( val ) VRRP_TIMER_SUB( val, VRRP_TIMER_CLK() ) 128 | #define VRRP_TIMER_EXPIRED( val ) ((val) && VRRP_TIMER_DELTA(val)<=0) 129 | #define VRRP_TIMER_CLR( val ) (val) = 0 130 | #define VRRP_TIMER_IS_RUNNING( val ) (val) 131 | #define VRRP_TIMER_HZ 1000000 132 | uint32_t VRRP_TIMER_CLK( void ) 133 | { 134 | struct timespec tv; 135 | uint32_t usecs = 0; 136 | clock_gettime(CLOCK_MONOTONIC,&tv ); 137 | usecs = (uint32_t)(tv.tv_nsec/1000); 138 | return tv.tv_sec*VRRP_TIMER_HZ+usecs; 139 | } 140 | 141 | 142 | #define VRRP_TIMER_SKEW( srv ) ((256-(srv)->priority)*VRRP_TIMER_HZ/256) 143 | 144 | #define VRRP_MIN( a , b ) ( (a) < (b) ? (a) : (b) ) 145 | #define VRRP_MAX( a , b ) ( (a) > (b) ? (a) : (b) ) 146 | 147 | #endif /* __VRRP_H__ */ 148 | 149 | 150 | --------------------------------------------------------------------------------