├── .gitignore
├── COPYING
├── Makefile.am
├── README.md
├── bits.h
├── common.h
├── configure.ac
├── list.h
├── log.c
├── log.h
├── uvrrpd.c
├── uvrrpd.h
├── vrrp.c
├── vrrp.h
├── vrrp_adv.c
├── vrrp_adv.h
├── vrrp_arp.c
├── vrrp_arp.h
├── vrrp_ctrl.c
├── vrrp_ctrl.h
├── vrrp_exec.c
├── vrrp_exec.h
├── vrrp_ip4.c
├── vrrp_ip6.c
├── vrrp_ipx.h
├── vrrp_na.c
├── vrrp_na.h
├── vrrp_net.c
├── vrrp_net.h
├── vrrp_options.c
├── vrrp_options.h
├── vrrp_rfc.h
├── vrrp_state.c
├── vrrp_state.h
├── vrrp_switch.sh
├── vrrp_timer.c
└── vrrp_timer.h
/.gitignore:
--------------------------------------------------------------------------------
1 | *.[oa]
2 | *.lo
3 | *~
4 | *.swp
5 | .libs/
6 | _libs/
7 | .deps/
8 | uvrrpd
9 | deploy.sh
10 | libtool
11 | Makefile.in
12 | Makefile
13 | aclocal.m4
14 | config/
15 | config.log
16 | config.status
17 | configure
18 | autom4te.cache/
19 |
--------------------------------------------------------------------------------
/COPYING:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 |
635 | Copyright (C)
636 |
637 | This program is free software: you can redistribute it and/or modify
638 | it under the terms of the GNU General Public License as published by
639 | the Free Software Foundation, either version 3 of the License, or
640 | (at your option) any later version.
641 |
642 | This program is distributed in the hope that it will be useful,
643 | but WITHOUT ANY WARRANTY; without even the implied warranty of
644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 | GNU General Public License for more details.
646 |
647 | You should have received a copy of the GNU General Public License
648 | along with this program. If not, see .
649 |
650 | Also add information on how to contact you by electronic and paper mail.
651 |
652 | If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 |
655 | Copyright (C)
656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 | This is free software, and you are welcome to redistribute it
658 | under certain conditions; type `show c' for details.
659 |
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License. Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 |
664 | You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 |
669 | The GNU General Public License does not permit incorporating your program
670 | into proprietary programs. If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library. If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License. But first, please read
674 | .
675 |
676 |
--------------------------------------------------------------------------------
/Makefile.am:
--------------------------------------------------------------------------------
1 | ACLOCAL_AMFLAGS = -I config
2 |
3 | sbin_SCRIPTS = vrrp_switch.sh
4 | EXTRA_DIST = vrrp_switch.sh
5 |
6 | AM_CPPFLAGS = $(DEBUG_OPTS) -DPATH="$(sbindir)" -DPATHRUN="$(localestatedir)/run"
7 |
8 | AM_CFLAGS = -Wall -W -Werror
9 |
10 | sbin_PROGRAMS = uvrrpd
11 |
12 | noinst_HEADERS = \
13 | bits.h \
14 | common.h \
15 | list.h \
16 | log.h \
17 | uvrrpd.h \
18 | vrrp_adv.h \
19 | vrrp_arp.h \
20 | vrrp_ctrl.h \
21 | vrrp_exec.h \
22 | vrrp.h \
23 | vrrp_ipx.h \
24 | vrrp_na.h \
25 | vrrp_net.h \
26 | vrrp_options.h \
27 | vrrp_rfc.h \
28 | vrrp_state.h \
29 | vrrp_timer.h
30 |
31 | uvrrpd_SOURCES = \
32 | log.c \
33 | uvrrpd.c \
34 | vrrp_adv.c \
35 | vrrp_arp.c \
36 | vrrp_ctrl.c \
37 | vrrp.c \
38 | vrrp_exec.c \
39 | vrrp_ip4.c \
40 | vrrp_ip6.c \
41 | vrrp_na.c \
42 | vrrp_net.c \
43 | vrrp_options.c \
44 | vrrp_state.c \
45 | vrrp_timer.c
46 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # uvrrpd
2 |
3 | uvrrpd is a VRRP daemon written in C, providing a full implementation of
4 | VRRPv2 (rfc3768) and VRRPv3 (rfc5798), with IPv4 and IPv6 support.
5 |
6 | uvrrpd is a project hosted at [Evolix's forge](https://forge.evolix.org/projects/uvrrpd)
7 |
8 | uvrrpd is written for GNU/Linux and use macvlan in order to derive multiple
9 | virtual NICs (virtual VRRP mac) from a single physical NIC.
10 |
11 | uvrrpd is a simply VRRP state machine, and a script (*vrrp_switch.sh*) is in
12 | charge to create or destroy Virtual VRRP interfaces.
13 |
14 | uvrrpd is designed to run a single VRRP instance, but you can run multiple
15 | instances of uvrrpd, each of them with a different VRRP id, on the same or
16 | different physical NIC.
17 |
18 | Simple text authentication from deprecated RFC2332 may be used while running
19 | uvrrpd in version 2 (rfc3768), but not in version 3 (rfc5798).
20 |
21 | It provides a network topology update by sending :
22 | - an ARP gratuitous packet for each Virtual VRRP IPv4 address specified in the
23 | VRRP instance,
24 | - an NDP neighbour advertisement for each Virtual VRRP IPv6 address.
25 |
26 | ## Building
27 |
28 | uvrrpd uses the autotools, so to build it from the released tarball, follow the
29 | usual procedure.
30 |
31 | ```
32 | ./configure
33 | make
34 | sudo make install
35 | ```
36 |
37 | If building from the git sources, run:
38 | ```
39 | autoreconf -i
40 | ```
41 | before that.
42 |
43 | That's all. You need the binary `uvrrpd` and the shell script *vrrp_switch.sh*
44 | to start playing, they are installed in $prefix/sbin, the default prefix being
45 | /usr/local.
46 |
47 | ## Usage
48 |
49 | ```
50 | $ ./uvrrpd -h
51 | Usage: uvrrpd -v vrid -i ifname [OPTIONS] VIP1 [… VIPn]
52 |
53 | Mandatory options:
54 | -v, --vrid vrid Virtual router identifier
55 | -i, --interface iface Interface
56 | VIP Virtual IP(s), 1 to 255 VIPs
57 |
58 | Optional arguments:
59 | -p, --priority prio Priority of VRRP Instance, (0-255, default 100)
60 | -t, --time delay Time interval between advertisements
61 | Seconds in VRRPv2 (default 1s),
62 | Centiseconds in VRRPv3 (default 100cs)
63 | -T, --start-delay delay Use custom delay in INIT state, override masterdown
64 | timer
65 | Seconds in VRRPv2 (default 0s),
66 | Centiseconds in VRRPv3 (default 0cs)
67 | -P, --preempt on|off Switch preempt (default on)
68 | -r, --rfc version Specify protocol 'version'
69 | 2 (VRRPv2, RFC3768) by default,
70 | 3 (VRRPv3, RFC5798)
71 | -6, --ipv6 IPv6 support, (only in VRRPv3)
72 | -a, --auth pass Simple text password (only in VRRPv2)
73 | -f, --foreground Execute uvrrpd in foreground
74 | -s, --script Path of hook script (default /usr/local/sbin/vrrp_switch.sh)
75 | -F --pidfile name Use alternate pid file 'name'
76 | Default /run/uvrrp_${vrid}.pid
77 | -C --control name Use alternate control file 'name'
78 | Default /run/uvrrpd_ctrl.${vrid}
79 | -d, --debug
80 | -h, --help
81 | ```
82 |
83 | ### Signals
84 |
85 | * `SIGHUP` : force uvrrpd to switch to init state
86 | * `SIGUSR1`|`SIGUSR2` : dump VRRP instance informations
87 |
88 | ### Control fifo
89 |
90 | User can send command through a control FIFO, by default in /var/run/uvrrpd_ctrl.${vrid}
91 |
92 | Commands available:
93 | * reload (force init state)
94 | * stop (exit)
95 | * state || status (dump vrrp status)
96 | * prio X (change priority while running, and switch to init state)
97 |
98 | ```
99 | # ./uvrrpd -v 42 -i eth0 10.0.0.254
100 | # echo "prio 90" > /var/run/uvrrpd_ctrl.42
101 | #
102 | # tail -10 /var/log/daemon.log
103 | […]
104 | uvrrpd[27820]: vrid 42 :: new prio 90 applied
105 | uvrrpd[27820]: vrid 42 :: init
106 | uvrrpd[27820]: vrid 42 :: init -> backup
107 | uvrrpd[27820]: vrid 42 :: masterdown_timer expired
108 | […]
109 | #
110 | ```
111 |
112 | ### Log
113 |
114 | LOG_DAEMON facility
115 |
116 | *vrrp_switch.sh* maintain a state file of the current instance in /tmp/state.vrrp_${vrid}_${ifname}
117 |
118 | ## Examples
119 |
120 | **uvrrpd must be run as root.**
121 |
122 | * Start a VRRP instance on eth0 interface with VRID 42, default priority (100),
123 | with *vrrp_switch.sh* in */usr/local/sbin/* directory.
124 |
125 | ```
126 | # ./uvrrpd -v 42 -i eth0 -s /usr/local/sbin/vrrp_switch.sh 10.0.0.254
127 | ```
128 |
129 | In our example, no other VRRP instance, we are the master and we can see the
130 | new VRRP interface with the VIP *10.0.0.254* and the virtual VRRP mac address
131 | *00:00:5e:00:01:2a* :
132 |
133 | ```
134 | # ifconfig
135 | eth0 Link encap:Ethernet HWaddr 52:54:00:4f:48:3f
136 | inet addr:10.0.0.1 Bcast:10.0.0.255 Mask:255.255.255.0
137 | inet6 addr: fe80::5054:ff:fe4f:483f/64 Scope:Link
138 | UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
139 | RX packets:4935 errors:0 dropped:0 overruns:0 frame:0
140 | TX packets:3835 errors:0 dropped:0 overruns:0 carrier:0
141 | collisions:0 txqueuelen:1000
142 | RX bytes:965166 (942.5 KiB) TX bytes:613308 (598.9 KiB)
143 |
144 | eth0_42 Link encap:Ethernet HWaddr 00:00:5e:00:01:2a
145 | inet addr:10.0.0.254 Bcast:0.0.0.0 Mask:255.255.255.255
146 | inet6 addr: fe80::200:5eff:fe00:12a/64 Scope:Link
147 | UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
148 | RX packets:12 errors:0 dropped:0 overruns:0 frame:0
149 | TX packets:6 errors:0 dropped:0 overruns:0 carrier:0
150 | collisions:0 txqueuelen:0
151 | RX bytes:3217 (3.1 KiB) TX bytes:520 (520.0 B)
152 | […]
153 | ```
154 |
155 | See logs :
156 |
157 | ```
158 | # tail -f /var/log/daemon.log
159 | […]
160 | uvrrpd[2966]: vrid 42 :: init
161 | uvrrpd[2966]: vrid 42 :: init -> backup
162 | uvrrpd[2966]: vrid 42 :: masterdown_timer expired
163 | uvrrpd[2966]: vrid 42 :: backup -> master
164 | ```
165 |
166 | and /tmp/state.vrrp_42_eth0 :
167 |
168 | ```
169 | # cat /tmp/state.vrrp_42_eth0
170 | state master
171 | vrid 42
172 | ifname eth0
173 | priority 100
174 | adv_int 1
175 | naddr 1
176 | ips 10.0.0.254
177 | ```
178 |
179 | You can start an another VRRP instance on another GNU/Linux box or a router with VRRP support, with the same VRID and different priority.
180 |
181 | * uvrrpd support IPv6 (RFC5798) :
182 |
183 | ```
184 | # ./uvrrpd -v 42 -i eth0 -p 90 -6 fe80::fada/64
185 | ```
186 |
187 | * Multiple VIPs could be specified for a single VRRP instance (up to 255 VIPs) :
188 |
189 | ```
190 | # ./uvrrpd -v 42 -i eth0 10.0.0.69 10.0.0.80
191 | ```
192 |
193 | ## TODOs
194 |
195 | * more tests
196 | * packaging
197 | * ...
198 |
199 | Any suggestions, ideas, patches or whatever are welcome and will be greatly
200 | appreciated !
201 |
--------------------------------------------------------------------------------
/bits.h:
--------------------------------------------------------------------------------
1 | /*
2 | * bits.h
3 | *
4 | * Copyright (C) 2014 Arnaud Andre
5 | *
6 | * This file is part of uvrrpd.
7 | *
8 | * uvrrpd is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU General Public License as published by
10 | * the Free Software Foundation, either version 3 of the License, or
11 | * (at your option) any later version.
12 | *
13 | * uvrrpd is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU General Public License
19 | * along with uvrrpd. If not, see .
20 | */
21 |
22 | #ifndef _BITS_H_
23 | #define _BITS_H_
24 |
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 |
32 | /**
33 | * BIT_MASK(nr) - bit mask
34 | */
35 | #define BIT_MASK(nr) (1 << (nr))
36 |
37 |
38 | /**
39 | * set_bit - Set a bit in memory
40 | */
41 | static inline void set_bit(int nr, unsigned long *addr)
42 | {
43 | *addr |= BIT_MASK(nr);
44 | }
45 |
46 | /**
47 | * clear_bit - Clear a bit in memory
48 | */
49 | static inline void clear_bit(int nr, unsigned long *addr)
50 | {
51 | *addr &= ~BIT_MASK(nr);
52 | }
53 |
54 | /**
55 | * change_bit - Toggle a bit in memory
56 | */
57 | static inline void change_bit(int nr, unsigned long *addr)
58 | {
59 | *addr ^= BIT_MASK(nr);
60 | }
61 |
62 | /**
63 | * test_and_set_bit - Set a bit and return its old value
64 | */
65 | static inline int test_and_set_bit(int nr, unsigned long *addr)
66 | {
67 | unsigned long mask = BIT_MASK(nr);
68 | unsigned long old = *addr;
69 |
70 | *addr = old | mask;
71 | return (old & mask) != 0;
72 | }
73 |
74 | /**
75 | * test_and_clear_bit - Clear a bit and return its old value
76 | */
77 | static inline int test_and_clear_bit(int nr, unsigned long *addr)
78 | {
79 | unsigned long mask = BIT_MASK(nr);
80 | unsigned long old = *addr;
81 |
82 | *addr = old & ~mask;
83 | return (old & mask) != 0;
84 | }
85 |
86 | /**
87 | * test_and_change_bit - Toggle a bit and return its old value
88 | */
89 | static inline int test_and_change_bit(int nr, unsigned long *addr)
90 | {
91 | unsigned long mask = BIT_MASK(nr);
92 | unsigned long old = *addr;
93 |
94 | *addr = old ^ mask;
95 | return (old & mask) != 0;
96 | }
97 |
98 | /**
99 | * test_bit - Determine whether a bit is set
100 | */
101 | static inline int test_bit(int nr, const unsigned long *addr)
102 | {
103 | return 1UL & (*addr >> nr);
104 | }
105 |
106 | #endif /* _BITS_H_ */
107 |
--------------------------------------------------------------------------------
/common.h:
--------------------------------------------------------------------------------
1 | /*
2 | * common.h - common types and macros
3 | *
4 | * Copyright (C) 2014 Arnaud Andre
5 | *
6 | * This file is part of uvrrpd.
7 | *
8 | * uvrrpd is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU General Public License as published by
10 | * the Free Software Foundation, either version 3 of the License, or
11 | * (at your option) any later version.
12 | *
13 | * uvrrpd is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU General Public License
19 | * along with uvrrpd. If not, see .
20 | */
21 |
22 |
23 | #ifndef _COMMON_H_
24 | #define _COMMON_H_
25 |
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 | #include
35 | #include "log.h"
36 |
37 | /**
38 | * bool - boolean type
39 | */
40 | typedef enum {
41 | FALSE,
42 | TRUE
43 | } bool;
44 |
45 | /**
46 | * matches( s, c_str ) - Compare strings.
47 | * s Data strings
48 | * c_str C-Strings
49 | */
50 | #define matches( s, c_str ) \
51 | ({ \
52 | const char __dummy[] = c_str; \
53 | (void)(&__dummy); \
54 | ( memcmp ( s, c_str, sizeof( c_str ) ) == 0 ); \
55 | })
56 |
57 | /**
58 | * stringify(x)
59 | */
60 | #define _stringify(x) #x
61 | #define stringify(x) _stringify(x)
62 |
63 | /**
64 | * ARRAY_SIZE()
65 | */
66 | #define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
67 |
68 | /**
69 | * max(a,b)
70 | */
71 | #define max(a,b) \
72 | ({ \
73 | __typeof__ (a) _a = (a); \
74 | __typeof__ (b) _b = (b); \
75 | _a > _b ? _a : _b; \
76 | })
77 |
78 | /**
79 | * WHITESPACE
80 | */
81 | #define WHITESPACE " \f\r\t\n\v"
82 |
83 | /**
84 | * cksum - compute IP checksum
85 | */
86 | static inline int unsigned short cksum(unsigned short *buf, int nbytes)
87 | {
88 | uint32_t sum;
89 | uint16_t oddbyte;
90 |
91 | sum = 0;
92 | while (nbytes > 1) {
93 | sum += *buf++;
94 | nbytes -= 2;
95 | }
96 |
97 | if (nbytes == 1) {
98 | oddbyte = 0;
99 | *((uint16_t *) & oddbyte) = *(uint16_t *) buf;
100 | sum += oddbyte;
101 | }
102 |
103 | sum = (sum >> 16) + (sum & 0xffff);
104 | sum += (sum >> 16);
105 |
106 | return (uint16_t) ~ sum;
107 | }
108 |
109 | /**
110 | * mystrtoul - convert a string to an unsigned long int
111 | */
112 | static inline int mystrtoul(unsigned long *const dest,
113 | const char *const str, unsigned long max)
114 | {
115 | unsigned long val;
116 | char *endptr;
117 |
118 | errno = 0;
119 | val = strtoull(str, &endptr, 0);
120 |
121 | if ((val == 0 || val == LONG_MAX) && errno == ERANGE)
122 | return -ERANGE;
123 |
124 | if (val > max)
125 | return -ERANGE;
126 |
127 | if (*endptr != '\0')
128 | return -EINVAL;
129 |
130 | *dest = val;
131 | return 0;
132 | }
133 |
134 | /**
135 | * is_file_executable
136 | */
137 | static inline int is_file_executable(const char *filename)
138 | {
139 | struct stat sb;
140 |
141 | if (stat(filename, &sb) == -1) {
142 | perror("stat");
143 | return 0;
144 | }
145 |
146 | if (S_ISREG(sb.st_mode) &&
147 | (sb.st_mode & S_IRUSR) && (sb.st_mode & S_IXUSR))
148 | return 1;
149 |
150 | return 0;
151 | }
152 |
153 |
154 | #define IP4_NMASK 32
155 | #define IP6_NMASK 128
156 | /**
157 | * split_ip_netmask() - split IPvX and netmask from a string
158 | */
159 | static inline int split_ip_netmask(int family,
160 | const char *str, void *addr,
161 | uint8_t * netmask)
162 | {
163 | char *tmp;
164 | unsigned long ul;
165 |
166 | int netmask_length, err;
167 |
168 | /* IPv4 */
169 | if (family == AF_INET)
170 | netmask_length = IP4_NMASK;
171 |
172 | /* IPv6 */
173 | if (family == AF_INET6)
174 | netmask_length = IP6_NMASK;
175 |
176 | tmp = strstr(str, "/");
177 | *netmask = 0;
178 |
179 | if (tmp != NULL) {
180 | *tmp = '\0';
181 | ++tmp;
182 | err = mystrtoul(&ul, tmp, netmask_length);
183 | if (err == -ERANGE) {
184 | log_error("%s", "CIDR netmask out of range");
185 | return err;
186 | }
187 | if (err == -EINVAL) {
188 | log_error("Error parsing %s as a number", tmp);
189 | return err;
190 | }
191 |
192 | if (netmask != NULL)
193 | *netmask = (uint8_t) ul;
194 | }
195 |
196 | if (inet_pton(family, str, addr) == 0) {
197 | log_error("inet_pton - %m");
198 | return -1;
199 | }
200 |
201 | return 0;
202 | }
203 |
204 |
205 | #ifdef DEBUG
206 | /**
207 | * print buf hexa
208 | */
209 | static inline void print_buf_hexa(const char *str, void *buf, size_t x)
210 | {
211 | uint8_t i;
212 | int j = 0;
213 |
214 | unsigned char *pbuf = (unsigned char *) buf;
215 |
216 | printf("*** %s ***\n", str);
217 |
218 | for (i = 0; i < x; ++i, ++j) {
219 | if (j == 4) {
220 | printf("\n");
221 | j = 0;
222 | }
223 | if (j > 0)
224 | printf(":");
225 | printf("%02X", pbuf[i]);
226 | }
227 | printf("\n");
228 | }
229 | #endif
230 |
231 | #endif /* _COMMON_H_ */
232 |
--------------------------------------------------------------------------------
/configure.ac:
--------------------------------------------------------------------------------
1 | AC_PREREQ(2.50)
2 | AC_INIT(uvrrpd, 0.1, arno@ankhoon.net)
3 | AC_CONFIG_AUX_DIR([config])
4 | AC_CONFIG_MACRO_DIR([config])
5 | AM_INIT_AUTOMAKE([foreign dist-xz tar-ustar])
6 | m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
7 | AC_CONFIG_SRCDIR(uvrrpd.c)
8 |
9 | AC_PROG_CC
10 | AC_PROG_CC_STDC dnl for -std=gnu99
11 | AC_USE_SYSTEM_EXTENSIONS dnl for -D_GNU_SOURCE
12 | AC_PROG_LIBTOOL
13 | AC_SEARCH_LIBS([clock_gettime],[rt posix4])
14 |
15 | AC_MSG_CHECKING(for debug options)
16 |
17 | DEBUG_OPTS=""
18 | AC_ARG_ENABLE(debug-logs,
19 | AS_HELP_STRING([--enable-debug-logs],[Enable debug logs]),
20 | [case "$enableval" in
21 | y | yes) DEBUG_OPTS="-DDEBUG";;
22 | esac])
23 |
24 | AC_ARG_ENABLE(asserts,
25 | AS_HELP_STRING([--disable-asserts],[Disable run-time assertions]),
26 | [case "$enableval" in
27 | n | no) DEBUG_OPTS="$DEBUG_OPTS -DNDEBUG";;
28 | esac])
29 |
30 | AC_MSG_RESULT(${DEBUG_OPTS:-none})
31 | AC_SUBST(DEBUG_OPTS)
32 |
33 | AC_ARG_ENABLE(ipv6,
34 | AS_HELP_STRING([--disable-ipv6],
35 | [disable ipv6 support (default is autodetect)]),
36 | uvrrpd_want_ipv6=$enable_ipv6,)
37 |
38 | dnl check for ipv6
39 | if test x"uvrrpd_want_ipv6" != xno; then
40 | AC_CHECK_TYPES(struct in6_addr,,,[#include ])
41 | AC_CHECK_TYPES(struct ip6_hdr,,,[#include ])
42 | AC_CHECK_DECLS(AF_INET6,,,[#include ])
43 | AC_MSG_CHECKING(for IPv6 headers and structures)
44 | uvrrpd_want_ipv6=no
45 |
46 | if test x"$ac_cv_type_struct_in6_addr" = xyes; then
47 | if test x"$ac_cv_type_struct_ip6_hdr" = xyes; then
48 | if test x"$ac_cv_have_decl_AF_INET6" = xyes; then
49 | uvrrpd_want_ipv6=yes
50 | fi
51 | fi
52 | fi
53 | AC_MSG_RESULT($uvrrpd_want_ipv6)
54 | fi
55 |
56 | dnl check for ipv6 multicast (required)
57 | if test x"uvrrpd_want_ipv6" != xno; then
58 | AC_CHECK_DECLS(IPV6_ADD_MEMBERSHIP,,,[#include ])
59 | AC_CHECK_TYPES(struct ipv6_mreq,,,[#include ])
60 | AC_MSG_CHECKING(for IPv6 multicast support)
61 | uvrrpd_want_ipv6_mcast=no
62 |
63 | if test x"$ac_cv_have_decl_IPV6_ADD_MEMBERSHIP" = xyes; then
64 | if test x"$ac_cv_type_struct_ipv6_mreq" = xyes; then
65 | uvrrpd_want_ipv6_mcast=yes
66 | AC_DEFINE([HAVE_IP6], 1, [Define to enable IPv6 support])
67 | fi
68 | fi
69 | AC_MSG_RESULT($uvrrpd_want_ipv6_mcast)
70 | fi
71 |
72 |
73 | AC_CONFIG_FILES([
74 | Makefile
75 | ])
76 |
77 | AC_OUTPUT()
78 |
--------------------------------------------------------------------------------
/list.h:
--------------------------------------------------------------------------------
1 | /**
2 | * list.h Copied from the Linux kernel source tree
3 | *
4 | * Implement doubly linked list (list_head)
5 | *
6 | * Licensed under the GPL v2 as per the whole kernel source tree.
7 | *
8 | */
9 |
10 | #ifndef _LIB_LIST_H_
11 | #define _LIB_LIST_H_
12 |
13 |
14 | #include
15 |
16 | /*!
17 | * container_of - cast a member of a descriptor out to the containing descriptor
18 | *
19 | * @ptr: the pointer to the member.
20 | * @type: the type of the container struct this is embedded in.
21 | * @member: the name of the member within the struct.
22 | *
23 | */
24 | #define container_of(ptr, type, member) ({ \
25 | typeof( ((type *)0)->member ) *__mptr = (ptr); \
26 | (type *)( (char *)__mptr - offsetof(type,member) );})
27 |
28 | /*!
29 | * These are non-NULL pointers that will result in page faults
30 | * under normal circumstances, used to verify that nobody uses
31 | * non-initialized list entries.
32 | */
33 | #define LIST_POISON1 ((void *) 0x00100100)
34 | #define LIST_POISON2 ((void *) 0x00200200)
35 |
36 | /*!
37 | * Simple doubly linked list implementation.
38 | *
39 | * Some of the internal functions ("__xxx") are useful when
40 | * manipulating whole lists rather than single entries, as
41 | * sometimes we already know the next/prev entries and we can
42 | * generate better code by using them directly rather than
43 | * using the generic single-entry routines.
44 | */
45 |
46 | struct list_head {
47 | struct list_head *next, *prev;
48 | };
49 |
50 | #define LIST_HEAD_INIT(name) { &(name), &(name) }
51 |
52 | #define LIST_HEAD(name) \
53 | struct list_head name = LIST_HEAD_INIT(name)
54 |
55 | static inline void INIT_LIST_HEAD(struct list_head *list)
56 | {
57 | list->next = list;
58 | list->prev = list;
59 | }
60 |
61 | /*!
62 | * Insert a new entry between two known consecutive entries.
63 | *
64 | * This is only for internal list manipulation where we know
65 | * the prev/next entries already!
66 | */
67 | static inline void
68 | __list_add(struct list_head *new,
69 | struct list_head *prev, struct list_head *next)
70 | {
71 | next->prev = new;
72 | new->next = next;
73 | new->prev = prev;
74 | prev->next = new;
75 | }
76 |
77 | /*!
78 | * list_add - add a new entry
79 | * @new: new entry to be added
80 | * @head: list head to add it after
81 | *
82 | * Insert a new entry after the specified head.
83 | * This is good for implementing stacks.
84 | */
85 | static inline void list_add(struct list_head *new, struct list_head *head)
86 | {
87 | __list_add(new, head, head->next);
88 | }
89 |
90 | /*!
91 | * list_add_tail - add a new entry
92 | * @new: new entry to be added
93 | * @head: list head to add it before
94 | *
95 | * Insert a new entry before the specified head.
96 | * This is useful for implementing queues.
97 | */
98 | static inline void list_add_tail(struct list_head *new, struct list_head *head)
99 | {
100 | __list_add(new, head->prev, head);
101 | }
102 |
103 | /*!
104 | * Delete a list entry by making the prev/next entries
105 | * point to each other.
106 | *
107 | * This is only for internal list manipulation where we know
108 | * the prev/next entries already!
109 | */
110 | static inline void __list_del(struct list_head *prev, struct list_head *next)
111 | {
112 | next->prev = prev;
113 | prev->next = next;
114 | }
115 |
116 | /*!
117 | * list_del - deletes entry from list.
118 | * @entry: the element to delete from the list.
119 | * Note: list_empty on entry does not return true after this, the entry is
120 | * in an undefined state.
121 | */
122 | static inline void list_del(struct list_head *entry)
123 | {
124 | __list_del(entry->prev, entry->next);
125 | entry->next = LIST_POISON1;
126 | entry->prev = LIST_POISON2;
127 | }
128 |
129 | /*!
130 | * list_del_init - deletes entry from list and reinitialize it.
131 | * @entry: the element to delete from the list.
132 | */
133 | static inline void list_del_init(struct list_head *entry)
134 | {
135 | __list_del(entry->prev, entry->next);
136 | INIT_LIST_HEAD(entry);
137 | }
138 |
139 | /**
140 | * list_replace - replace old entry by new one
141 | * @old : the element to be replaced
142 | * @new : the new element to insert
143 | *
144 | * If @old was empty, it will be overwritten.
145 | */
146 | static inline void list_replace(struct list_head *old, struct list_head *new)
147 | {
148 | new->next = old->next;
149 | new->next->prev = new;
150 | new->prev = old->prev;
151 | new->prev->next = new;
152 | }
153 |
154 | static inline void
155 | list_replace_init(struct list_head *old, struct list_head *new)
156 | {
157 | list_replace(old, new);
158 | INIT_LIST_HEAD(old);
159 | }
160 |
161 | /*!
162 | * list_swap - swap elements from list
163 | * @a: the entry to move to a
164 | * @b: the entry to move to b
165 | */
166 | static inline void list_swap(struct list_head *a, struct list_head *b)
167 | {
168 | if (a->next == b) {
169 | list_replace(a, b);
170 | list_add(b, a);
171 | }
172 | else if (a->prev == b) {
173 | list_replace(b, a);
174 | list_add(a, b);
175 | }
176 | else {
177 | struct list_head tmp;
178 |
179 | tmp.next = b->next;
180 | tmp.prev = b->prev;
181 | list_replace(a, b);
182 | list_replace(&tmp, a);
183 | }
184 | }
185 |
186 | /*!
187 | * list_move - delete from one list and add as another's head
188 | * @list: the entry to move
189 | * @head: the head that will precede our entry
190 | */
191 | static inline void list_move(struct list_head *list, struct list_head *head)
192 | {
193 | __list_del(list->prev, list->next);
194 | list_add(list, head);
195 | }
196 |
197 | /*!
198 | * list_move_tail - delete from one list and add as another's tail
199 | * @list: the entry to move
200 | * @head: the head that will follow our entry
201 | */
202 | static inline void
203 | list_move_tail(struct list_head *list, struct list_head *head)
204 | {
205 | __list_del(list->prev, list->next);
206 | list_add_tail(list, head);
207 | }
208 |
209 | /**
210 | * list_is_last - tests whether @list is the last entry in list @head
211 | * @list: the entry to test
212 | * @head: the head of the list
213 | */
214 | static inline int
215 | list_is_last(const struct list_head *list, const struct list_head *head)
216 | {
217 | return list->next == head;
218 | }
219 |
220 | /*!
221 | * list_empty - tests whether a list is empty
222 | * @head: the list to test.
223 | */
224 | static inline int list_empty(struct list_head const *head)
225 | {
226 | return head->next == head;
227 | }
228 |
229 | static inline void __list_splice(struct list_head *list, struct list_head *head)
230 | {
231 | struct list_head *first = list->next;
232 | struct list_head *last = list->prev;
233 | struct list_head *at = head->next;
234 |
235 | first->prev = head;
236 | head->next = first;
237 |
238 | last->next = at;
239 | at->prev = last;
240 | }
241 |
242 | /*!
243 | * list_splice - join two lists
244 | * @list: the new list to add.
245 | * @head: the place to add it in the first list.
246 | */
247 | static inline void list_splice(struct list_head *list, struct list_head *head)
248 | {
249 | if (!list_empty(list))
250 | __list_splice(list, head);
251 | }
252 |
253 | /*!
254 | * list_splice_init - join two lists and reinitialise the emptied list.
255 | * @list: the new list to add.
256 | * @head: the place to add it in the first list.
257 | *
258 | * The list at @list is reinitialised
259 | */
260 | static inline void
261 | list_splice_init(struct list_head *list, struct list_head *head)
262 | {
263 | if (!list_empty(list)) {
264 | __list_splice(list, head);
265 | INIT_LIST_HEAD(list);
266 | }
267 | }
268 |
269 | /*!
270 | * list_entry - get the struct for this entry
271 | * @ptr: the &struct list_head pointer.
272 | * @type: the type of the struct this is embedded in.
273 | * @member: the name of the list_struct within the struct.
274 | */
275 | #define list_entry(ptr, type, member) \
276 | container_of(ptr, type, member)
277 |
278 | /**
279 | * list_first_entry - get the first element from a list
280 | * @ptr: the list head to take the element from.
281 | * @type: the type of the struct this is embedded in.
282 | * @member: the name of the list_struct within the struct.
283 | *
284 | * Note, that list is expected to be not empty.
285 | */
286 | #define list_first_entry(ptr, type, member) \
287 | list_entry((ptr)->next, type, member)
288 |
289 | /*!
290 | * list_for_each - iterate over a list
291 | * @pos: the &struct list_head to use as a loop counter.
292 | * @head: the head for your list.
293 | */
294 | #define list_for_each(pos, head) \
295 | for (pos = (head)->next; pos != (head); pos = pos->next)
296 |
297 | /*!
298 | * list_for_each_prev - iterate over a list backwards
299 | * @pos: the &struct list_head to use as a loop counter.
300 | * @head: the head for your list.
301 | */
302 | #define list_for_each_prev(pos, head) \
303 | for (pos = (head)->prev; pos != (head); pos = pos->prev)
304 |
305 | /*!
306 | * list_for_each_safe - iterate over a list safe against removal of list entry
307 | * @pos: the &struct list_head to use as a loop counter.
308 | * @n: another &struct list_head to use as temporary storage
309 | * @head: the head for your list.
310 | */
311 | #define list_for_each_safe(pos, n, head) \
312 | for (pos = (head)->next, n = pos->next; pos != (head); \
313 | pos = n, n = pos->next)
314 |
315 | /*!
316 | * list_for_each_entry - iterate over list of given type
317 | * @pos: the type * to use as a loop counter.
318 | * @head: the head for your list.
319 | * @member: the name of the list_struct within the struct.
320 | */
321 | #define list_for_each_entry(pos, head, member) \
322 | for (pos = list_entry((head)->next, typeof(*pos), member); \
323 | &pos->member != (head); \
324 | pos = list_entry(pos->member.next, typeof(*pos), member))
325 |
326 | /*!
327 | * list_for_each_entry_reverse - iterate backwards over list of given type.
328 | * @pos: the type * to use as a loop counter.
329 | * @head: the head for your list.
330 | * @member: the name of the list_struct within the struct.
331 | */
332 | #define list_for_each_entry_reverse(pos, head, member) \
333 | for (pos = list_entry((head)->prev, typeof(*pos), member); \
334 | &pos->member != (head); \
335 | pos = list_entry(pos->member.prev, typeof(*pos), member))
336 |
337 | /**
338 | * list_for_each_entry_continue - continue iteration over list of given type
339 | * @pos: the type * to use as a loop cursor.
340 | * @head: the head for your list.
341 | * @member: the name of the list_struct within the struct.
342 | *
343 | * Continue to iterate over list of given type, continuing after
344 | * the current position.
345 | */
346 | #define list_for_each_entry_continue(pos, head, member) \
347 | for (pos = list_entry(pos->member.next, typeof(*pos), member); \
348 | &pos->member != (head); \
349 | pos = list_entry(pos->member.next, typeof(*pos), member))
350 |
351 | /**
352 | * list_for_each_entry_from - iterate over list of given type from the current point
353 | * @pos: the type * to use as a loop cursor.
354 | * @head: the head for your list.
355 | * @member: the name of the list_struct within the struct.
356 | *
357 | * Iterate over list of given type, continuing from current position.
358 | */
359 | #define list_for_each_entry_from(pos, head, member) \
360 | for (; &pos->member != (head); \
361 | pos = list_entry(pos->member.next, typeof(*pos), member))
362 |
363 | /*!
364 | * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
365 | * @pos: the type * to use as a loop counter.
366 | * @n: another type * to use as temporary storage
367 | * @head: the head for your list.
368 | * @member: the name of the list_struct within the struct.
369 | */
370 | #define list_for_each_entry_safe(pos, n, head, member) \
371 | for (pos = list_entry((head)->next, typeof(*pos), member), \
372 | n = list_entry(pos->member.next, typeof(*pos), member); \
373 | &pos->member != (head); \
374 | pos = n, n = list_entry(n->member.next, typeof(*n), member))
375 |
376 | /**
377 | * list_for_each_entry_safe_continue
378 | * @pos: the type * to use as a loop cursor.
379 | * @n: another type * to use as temporary storage
380 | * @head: the head for your list.
381 | * @member: the name of the list_struct within the struct.
382 | *
383 | * Iterate over list of given type, continuing after current point,
384 | * safe against removal of list entry.
385 | */
386 | #define list_for_each_entry_safe_continue(pos, n, head, member) \
387 | for (pos = list_entry(pos->member.next, typeof(*pos), member), \
388 | n = list_entry(pos->member.next, typeof(*pos), member); \
389 | &pos->member != (head); \
390 | pos = n, n = list_entry(n->member.next, typeof(*n), member))
391 |
392 | /**
393 | * list_for_each_entry_safe_from
394 | * @pos: the type * to use as a loop cursor.
395 | * @n: another type * to use as temporary storage
396 | * @head: the head for your list.
397 | * @member: the name of the list_struct within the struct.
398 | *
399 | * Iterate over list of given type from current point, safe against
400 | * removal of list entry.
401 | */
402 | #define list_for_each_entry_safe_from(pos, n, head, member) \
403 | for (n = list_entry(pos->member.next, typeof(*pos), member); \
404 | &pos->member != (head); \
405 | pos = n, n = list_entry(n->member.next, typeof(*n), member))
406 |
407 | /**
408 | * list_for_each_entry_safe_reverse
409 | * @pos: the type * to use as a loop cursor.
410 | * @n: another type * to use as temporary storage
411 | * @head: the head for your list.
412 | * @member: the name of the list_struct within the struct.
413 | *
414 | * Iterate backwards over list of given type, safe against removal
415 | * of list entry.
416 | */
417 | #define list_for_each_entry_safe_reverse(pos, n, head, member) \
418 | for (pos = list_entry((head)->prev, typeof(*pos), member), \
419 | n = list_entry(pos->member.prev, typeof(*pos), member); \
420 | &pos->member != (head); \
421 | pos = n, n = list_entry(n->member.prev, typeof(*n), member))
422 |
423 |
424 | #endif /* _LIB_LIST_H_ */
425 |
--------------------------------------------------------------------------------
/log.c:
--------------------------------------------------------------------------------
1 | /*
2 | * log.c
3 | *
4 | * Copyright (C) 2014 Arnaud Andre
5 | *
6 | * This file is part of uvrrpd.
7 | *
8 | * uvrrpd is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU General Public License as published by
10 | * the Free Software Foundation, either version 3 of the License, or
11 | * (at your option) any later version.
12 | *
13 | * uvrrpd is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU General Public License
19 | * along with uvrrpd. If not, see .
20 | */
21 |
22 | /* ISO C */
23 | #include
24 | #include
25 | #include
26 |
27 | /* POSIX */
28 | #include
29 |
30 | #include "common.h"
31 |
32 | #ifdef DEBUG
33 | int __log_trigger = LOG_DEBUG;
34 | #else
35 | int __log_trigger = LOG_NOTICE;
36 | #endif
37 |
38 | int log_trigger(char const *level)
39 | {
40 | /*
41 | * LOG_ERR error conditions
42 | * LOG_WARNING warning conditions
43 | * LOG_NOTICE normal, but significant, condition
44 | * LOG_INFO informational message
45 | * LOG_DEBUG
46 | */
47 | if (level == NULL) {
48 | return __log_trigger;
49 | }
50 | else if (matches(level, "err")) {
51 | __log_trigger = LOG_ERR;
52 | }
53 | else if (matches(level, "warning")) {
54 | __log_trigger = LOG_WARNING;
55 | }
56 | else if (matches(level, "notice")) {
57 | __log_trigger = LOG_NOTICE;
58 | }
59 | else if (matches(level, "info")) {
60 | __log_trigger = LOG_INFO;
61 | }
62 | else if (matches(level, "debug")) {
63 | __log_trigger = LOG_DEBUG;
64 | }
65 |
66 | return __log_trigger;
67 | }
68 |
69 | void log_open(char const *app, char const *level)
70 | {
71 | openlog(app ? app : "-", LOG_PERROR | LOG_PID, LOG_DAEMON);
72 | log_trigger(level);
73 | }
74 |
75 | void log_close(void)
76 | {
77 | closelog();
78 | }
79 |
80 | void log_it(int priority, char const *format, ...)
81 | {
82 | va_list ap;
83 |
84 | va_start(ap, format);
85 | vsyslog(priority, format, ap);
86 | va_end(ap);
87 | }
88 |
--------------------------------------------------------------------------------
/log.h:
--------------------------------------------------------------------------------
1 | /*
2 | * log.h
3 | *
4 | * Copyright (C) 2014 Arnaud Andre
5 | *
6 | * This file is part of uvrrpd.
7 | *
8 | * uvrrpd is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU General Public License as published by
10 | * the Free Software Foundation, either version 3 of the License, or
11 | * (at your option) any later version.
12 | *
13 | * uvrrpd is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU General Public License
19 | * along with uvrrpd. If not, see .
20 | */
21 |
22 | #ifndef _LOG_H_
23 | #define _LOG_H_
24 |
25 |
26 | /* ISO C */
27 | #include
28 | #include
29 |
30 | /* POSIX */
31 | #include
32 |
33 | /**
34 | * log_trigger (char const *level)
35 | * Set up logs level trigger. If level is NULL return current level trigger
36 | * - err Error conditions
37 | * - warning Warning conditions
38 | * - notice Normal, but significant, condition
39 | * - info Informational message
40 | * - debug Debug message
41 | */
42 | int log_trigger(char const *level);
43 |
44 | /**
45 | * log_open (char const *app, char const *level)
46 | * Open logs system. Define logs level trigger.
47 | * @app Application name
48 | * @level Logs level
49 | */
50 | void log_open(char const *app, char const *level);
51 |
52 | /**
53 | * log_close( void )
54 | * Close logs system.
55 | */
56 | void log_close(void);
57 |
58 | /**
59 | * log_it( int priority, char const *format, ...)
60 | * Log message if priority is higher than level trigger
61 | * @priority Message
62 | * @format Log message
63 | * @... Arguments list
64 | */
65 | void log_it(int priority, char const *format, ...)
66 | __attribute__ ((__format__(__printf__, 2, 3)));
67 |
68 | /**
69 | * log_error( fmt, ... )
70 | * @fmt Log message
71 | * @... Arguments list
72 | */
73 | #define log_error( fmt, ... ) \
74 | do { \
75 | log_it( LOG_ERR, "%s::%s "fmt, \
76 | "error", __func__, ##__VA_ARGS__ ); \
77 | } while ( 0 )
78 |
79 | /**
80 | * log_sys_error( fmt, ... )
81 | * @fmt Log message
82 | * @... Arguments list
83 | */
84 | #define log_sys_error( fmt, ... ) \
85 | do { \
86 | log_it( LOG_ERR, "%s::%s "fmt" %s", \
87 | "error", __func__, ##__VA_ARGS__, strerror(errno) ); \
88 | } while ( 0 )
89 |
90 | /**
91 | * log_warning( fmt, ... )
92 | * @fmt Log message
93 | * @... Arguments list
94 | */
95 | #define log_warning( fmt, ... ) \
96 | do { \
97 | log_it( LOG_WARNING, "%s::%s "fmt, \
98 | "warning", __func__, ##__VA_ARGS__ ); \
99 | } while ( 0 )
100 |
101 | /**
102 | * log_notice( ... )
103 | * @... Log message and arguments list
104 | */
105 | #define log_notice( ... ) \
106 | do { \
107 | log_it( LOG_NOTICE, ##__VA_ARGS__ ); \
108 | } while ( 0 )
109 |
110 | /**
111 | * log_info( ... )
112 | * Log message. Enable in info or higher level
113 | * @... Log message and arguments list
114 | */
115 | #define log_info( ... ) \
116 | do { \
117 | extern int __log_trigger; \
118 | \
119 | if ( LOG_INFO <= __log_trigger ) \
120 | log_it( LOG_INFO, ##__VA_ARGS__ ); \
121 | } while ( 0 )
122 |
123 | /**
124 | * log_debug( fmt, ... )
125 | * Log message. Enable in debug level
126 | * @fmt Log message
127 | * @... Arguments list
128 | */
129 | #define log_debug( fmt, ... ) \
130 | do { \
131 | extern int __log_trigger; \
132 | \
133 | if ( LOG_DEBUG <= __log_trigger ) \
134 | log_it( LOG_DEBUG, "%s %s "fmt, \
135 | "--- DEBUG ---", __func__, ##__VA_ARGS__ ); \
136 | } while ( 0 )
137 |
138 | #ifdef DEBUG
139 | /**
140 | * log_devel( fmt, ... )
141 | * Log message. Enable in devel level
142 | * @fmt Log message
143 | * @... Arguments list
144 | */
145 | #define log_devel( fmt, ... ) \
146 | do { \
147 | extern int __log_trigger; \
148 | \
149 | if ( LOG_DEBUG <= __log_trigger ) \
150 | log_it( LOG_DEBUG, "%s %s( " fmt " )", \
151 | "--- DEVEL ---", __func__, ##__VA_ARGS__ ); \
152 | } while ( 0 )
153 | #else
154 | #define log_devel( fmt, ... )
155 | #endif /* DEBUG */
156 |
157 |
158 | #endif /* _LOG_H_ */
159 |
--------------------------------------------------------------------------------
/uvrrpd.c:
--------------------------------------------------------------------------------
1 | /*
2 | * uvrrpd.c - main entry point, server initialization
3 | *
4 | * Copyright (C) 2014 Arnaud Andre
5 | *
6 | * This file is part of uvrrpd.
7 | *
8 | * uvrrpd is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU General Public License as published by
10 | * the Free Software Foundation, either version 3 of the License, or
11 | * (at your option) any later version.
12 | *
13 | * uvrrpd is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU General Public License
19 | * along with uvrrpd. If not, see .
20 | */
21 |
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #ifdef _POSIX_PRIORITY_SCHEDULING
29 | #include
30 | #else
31 | #warning "no sched rt"
32 | #endif
33 |
34 | #include "uvrrpd.h"
35 | #include "vrrp.h"
36 | #include "vrrp_net.h"
37 | #include "vrrp_adv.h"
38 | #include "vrrp_arp.h"
39 | #ifdef HAVE_IP6
40 | #include "vrrp_na.h"
41 | #endif
42 | #include "vrrp_options.h"
43 | #include "vrrp_exec.h"
44 | #include "vrrp_ctrl.h"
45 |
46 | #include "log.h"
47 |
48 | /* global constants */
49 | unsigned long reg = 0UL;
50 | int background = 1;
51 | char *loglevel = NULL;
52 | char *pidfile_name = NULL;
53 | char *ctrlfile_name = NULL;
54 |
55 | /* local methods */
56 | static void signal_handler(int sig);
57 | static void signal_setup(void);
58 | static int pidfile_init(int vrid);
59 | static void pidfile_unlink(void);
60 | static void pidfile_check(int vrid);
61 | static void pidfile(int vrid);
62 | static int ctrlfile_init(int vrid);
63 | static void ctrlfile_unlink(void);
64 | static void ctrlfile(int vrid, int *fd);
65 |
66 | /**
67 | * main() - entry point
68 | *
69 | * Declare VRRP instance, init daemon
70 | * and launch state machine
71 | */
72 | int main(int argc, char *argv[])
73 | {
74 | signal_setup();
75 |
76 | /* Current VRRP instance */
77 | struct vrrp vrrp;
78 | struct vrrp_net vnet;
79 |
80 | /* Init VRRP instance */
81 | vrrp_init(&vrrp);
82 | vrrp_net_init(&vnet);
83 |
84 | /* cmdline options */
85 | if (! !vrrp_options(&vrrp, &vnet, argc, argv))
86 | exit(EXIT_FAILURE);
87 |
88 | /* pidfile init && check */
89 | if (pidfile_init(vrrp.vrid) != 0)
90 | exit(EXIT_FAILURE);
91 |
92 | pidfile_check(vrrp.vrid);
93 |
94 | /* logs */
95 | log_open("uvrrpd", (char const *) loglevel);
96 |
97 | /* init and open control file fifo */
98 | ctrlfile_init(vrrp.vrid);
99 | ctrlfile(vrrp.vrid, &vrrp.ctrl.fd);
100 | if (vrrp_ctrl_init(&vrrp.ctrl) != 0)
101 | exit(EXIT_FAILURE);
102 |
103 | /* open sockets */
104 | if ((vrrp_net_socket(&vnet) != 0) || (vrrp_net_socket_xmit(&vnet) != 0))
105 | exit(EXIT_FAILURE);
106 |
107 | /* hook script */
108 | if (vrrp_exec_init(&vrrp) != 0)
109 | exit(EXIT_FAILURE);
110 |
111 | /* advertisement pkt */
112 | if (vrrp_adv_init(&vnet, &vrrp) != 0)
113 | exit(EXIT_FAILURE);
114 |
115 | /* net topology */
116 | if (vnet.family == AF_INET) {
117 | if (vrrp_arp_init(&vnet) != 0)
118 | exit(EXIT_FAILURE);
119 | }
120 | #ifdef HAVE_IP6
121 | else if (vnet.family == AF_INET6) {
122 | if (vrrp_na_init(&vnet) != 0)
123 | exit(EXIT_FAILURE);
124 | }
125 | #endif
126 |
127 | /* daemonize */
128 | if (background) {
129 | if (daemon(0, (log_trigger(NULL) > LOG_INFO)) != 0) {
130 | log_error("vrid %d :: daemon - %m", vrrp.vrid);
131 | exit(EXIT_FAILURE);
132 | }
133 | }
134 | else {
135 | if (chdir("/") != 0) {
136 | log_error("vrid %d :: chdir - %m", vrrp.vrid);
137 | exit(EXIT_FAILURE);
138 | }
139 | }
140 |
141 | /* pidfile */
142 | pidfile(vrrp.vrid);
143 |
144 | /* lock procress's virtual address space into RAM */
145 | mlockall(MCL_CURRENT | MCL_FUTURE);
146 | /* set SCHED_RR */
147 | uvrrpd_sched_set();
148 |
149 | /* process */
150 | set_bit(KEEP_GOING, ®);
151 | while (test_bit(KEEP_GOING, ®) && !vrrp_process(&vrrp, &vnet));
152 |
153 | /* shutdown */
154 | vrrp_adv_cleanup(&vnet);
155 |
156 | if (vnet.family == AF_INET)
157 | vrrp_arp_cleanup(&vnet);
158 | #ifdef HAVE_IP6
159 | else /* AF_INET6 */
160 | vrrp_na_cleanup(&vnet);
161 | #endif
162 |
163 | vrrp_cleanup(&vrrp);
164 | vrrp_exec_cleanup(&vrrp);
165 | vrrp_ctrl_cleanup(&vrrp.ctrl);
166 | vrrp_net_cleanup(&vnet);
167 |
168 | log_close();
169 | free(loglevel);
170 | pidfile_unlink();
171 | ctrlfile_unlink();
172 | free(pidfile_name);
173 |
174 | munlockall();
175 |
176 | return EXIT_SUCCESS;
177 | }
178 |
179 |
180 | /**
181 | * signal_handler - Signal handler
182 | */
183 | static void signal_handler(int sig)
184 | {
185 | switch (sig) {
186 | case SIGHUP:
187 | log_notice("HUP to the init state");
188 | set_bit(UVRRPD_RELOAD, ®);
189 | break;
190 |
191 | case SIGUSR1:
192 | case SIGUSR2:
193 | set_bit(UVRRPD_DUMP, ®);
194 | break;
195 |
196 | case SIGPIPE:
197 | log_notice("this is not a SIGPIPE");
198 | set_bit(UVRRPD_LOGOUT, ®);
199 | break;
200 |
201 | case SIGINT:
202 | case SIGTERM:
203 | case SIGQUIT:
204 | log_notice("%s - exit daemon", strsignal(sig));
205 | set_bit(UVRRPD_RELOAD, ®);
206 | clear_bit(KEEP_GOING, ®);
207 | break;
208 |
209 | case SIGCHLD:
210 | /* bleh */
211 | break;
212 |
213 | default:
214 | log_error("%s %d", strsignal(sig), sig);
215 | break;
216 | }
217 | }
218 |
219 | /**
220 | * signal_setup
221 | * - register signal handler
222 | * - SIGTERM: shutdown daemon
223 | * - SIGHUP: reload daemon (switch to init state)
224 | * - SIGCHLD: notify end of task (vrrp_exec())
225 | * - SIGUSR1: logs daemon context: vrrp_context()
226 | * - SIGUSR2: todo, same as USR1 for the moment
227 | * - SIGPIPE: socket write failure
228 | *
229 | * - blocked signal, unblocked them on select() syscall vrrp_process()
230 | */
231 | static void signal_setup(void)
232 | {
233 | struct sigaction sa;
234 |
235 | /* setup signal */
236 | memset(&sa, 0x00, sizeof(sa));
237 | sa.sa_handler = signal_handler;
238 | sa.sa_flags = 0;
239 |
240 | sigaction(SIGINT, &sa, NULL);
241 | sigaction(SIGTERM, &sa, NULL);
242 | sigaction(SIGQUIT, &sa, NULL);
243 | sigaction(SIGHUP, &sa, NULL);
244 | sigaction(SIGCHLD, &sa, NULL);
245 | sigaction(SIGUSR1, &sa, NULL);
246 | sigaction(SIGUSR2, &sa, NULL);
247 | sigaction(SIGALRM, &sa, NULL);
248 | sigaction(SIGPIPE, &sa, NULL);
249 |
250 | /* setup signal mask */
251 | sigemptyset(&sa.sa_mask);
252 |
253 | sigaddset(&sa.sa_mask, SIGINT);
254 | sigaddset(&sa.sa_mask, SIGTERM);
255 | sigaddset(&sa.sa_mask, SIGQUIT);
256 | sigaddset(&sa.sa_mask, SIGHUP);
257 | sigaddset(&sa.sa_mask, SIGUSR1);
258 | sigaddset(&sa.sa_mask, SIGUSR2);
259 |
260 | sigprocmask(SIG_BLOCK, &sa.sa_mask, NULL);
261 | }
262 |
263 | /**
264 | * pidfile_init()
265 | */
266 | static int pidfile_init(int vrid)
267 | {
268 | int max_len = NAME_MAX + PATH_MAX;
269 | if (pidfile_name == NULL) {
270 | pidfile_name = malloc(max_len);
271 | if (pidfile_name == NULL) {
272 | log_error("vrid %d :: malloc - %m", vrid);
273 | return -1;
274 | }
275 |
276 | snprintf(pidfile_name, max_len, PIDFILE_NAME, vrid);
277 | }
278 |
279 | return 0;
280 | }
281 |
282 | /**
283 | * pidfile_unlink() - remove pidfile
284 | */
285 | static void pidfile_unlink(void)
286 | {
287 | if (pidfile_name)
288 | unlink(pidfile_name);
289 | }
290 |
291 | /**
292 | * pidfile_check()
293 | */
294 | static void pidfile_check(int vrid)
295 | {
296 | struct flock fl;
297 | int err, fd;
298 |
299 | fd = open(pidfile_name, O_RDONLY | O_CLOEXEC);
300 | if (fd < 0) {
301 | if (errno == ENOENT)
302 | return;
303 | fprintf(stderr, "vrid %d :: error opening PID file %s: %m\n",
304 | vrid, pidfile_name);
305 | exit(EXIT_FAILURE);
306 | }
307 |
308 | fl.l_type = F_WRLCK;
309 | fl.l_whence = SEEK_SET;
310 | fl.l_start = 0;
311 | fl.l_len = 0;
312 |
313 | err = fcntl(fd, F_GETLK, &fl);
314 | close(fd);
315 | if (err < 0) {
316 | fprintf(stderr, "vrid %d :: error getting PID file %s lock: %m",
317 | vrid, pidfile_name);
318 | exit(EXIT_FAILURE);
319 | }
320 |
321 | if (fl.l_type == F_UNLCK)
322 | return;
323 |
324 | fprintf(stderr, "vrid %d :: uvrrpd is already running (pid %d)\n", vrid,
325 | (int) fl.l_pid);
326 | exit(EXIT_FAILURE);
327 | }
328 |
329 | /**
330 | * pid_file()
331 | */
332 | static void pidfile(int vrid)
333 | {
334 | struct flock fl;
335 | char buf[16];
336 | int err, fd;
337 |
338 | fd = open(pidfile_name,
339 | O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR);
340 | if (fd < 0) {
341 | log_error("vrid %d :: error opening PID file %s: %m", vrid,
342 | pidfile_name);
343 | exit(EXIT_FAILURE);
344 | }
345 |
346 | fl.l_type = F_WRLCK;
347 | fl.l_whence = SEEK_SET;
348 | fl.l_start = 0;
349 | fl.l_len = 0;
350 |
351 | err = fcntl(fd, F_SETLK, &fl);
352 | if (err < 0) {
353 | if (errno == EACCES || errno == EAGAIN) {
354 | log_error("vrid %d :: uvrrpd is already running",
355 | vrid);
356 | exit(EXIT_FAILURE);
357 | }
358 | log_error("vrid %d :: error setting PID file %s lock: %m",
359 | vrid, pidfile_name);
360 | exit(EXIT_FAILURE);
361 | }
362 |
363 | atexit(pidfile_unlink);
364 |
365 | err = snprintf(buf, sizeof(buf), "%d\n", (int) getpid());
366 | if (err < 0) {
367 | perror("snprintf");
368 | exit(EXIT_FAILURE);
369 | }
370 |
371 | err = write(fd, buf, err);
372 | if (err < 0) {
373 | log_error("vrid %d :: error writing PID to PID file %s: %m",
374 | vrid, pidfile_name);
375 | exit(EXIT_FAILURE);
376 | }
377 | }
378 |
379 |
380 | /**
381 | * ctrlfile_init()
382 | */
383 | static int ctrlfile_init(int vrid)
384 | {
385 | int max_len = NAME_MAX + PATH_MAX;
386 | if (ctrlfile_name == NULL) {
387 | ctrlfile_name = malloc(max_len);
388 | if (ctrlfile_name == NULL) {
389 | log_error("vrid %d :: malloc - %m", vrid);
390 | return -1;
391 | }
392 |
393 | snprintf(ctrlfile_name, max_len, CTRLFILE_NAME, vrid);
394 | }
395 |
396 | return 0;
397 | }
398 |
399 | /**
400 | * ctrlfile_unlink()
401 | */
402 | static void ctrlfile_unlink()
403 | {
404 | if (ctrlfile_name)
405 | unlink(ctrlfile_name);
406 | }
407 |
408 | /**
409 | * ctrlfile()
410 | */
411 | static void ctrlfile(int vrid, int *fd)
412 | {
413 | if (fd == NULL) {
414 | log_error("vrid %d :: invalid use of ctrlfile(), fd NULL", vrid);
415 | exit(EXIT_FAILURE);
416 | }
417 |
418 | ctrlfile_unlink();
419 | if (mkfifo(ctrlfile_name, 0600) != 0) {
420 | log_error("vrid %d :: error while creating control fifo %s: %m", vrid,
421 | ctrlfile_name);
422 | exit(EXIT_FAILURE);
423 | }
424 |
425 | atexit(ctrlfile_unlink);
426 |
427 | *fd = open(ctrlfile_name, O_RDWR | O_NONBLOCK);
428 | if (*fd == -1) {
429 | log_error("vrid %d :: error while opening control fifo %s: %m", vrid,
430 | ctrlfile_name);
431 | exit(EXIT_FAILURE);
432 | }
433 | }
434 |
435 | /**
436 | * uvrrpd_sched_set() - set SCHED_RR scheduler
437 | */
438 | int uvrrpd_sched_set()
439 | {
440 | #ifdef _POSIX_PRIORITY_SCHEDULING
441 | struct sched_param param;
442 |
443 | param.sched_priority = sched_get_priority_max(SCHED_RR);
444 | if (sched_setscheduler(0, SCHED_RR, ¶m) != 0) {
445 | log_error("sched_setscheduler() - %m");
446 | return -1;
447 | }
448 | #else
449 | nice(-20);
450 | #endif
451 |
452 | return 0;
453 | }
454 |
455 | /**
456 | * uvrrpd_sched_unset() - unset SCHED_RR scheduler
457 | */
458 | int uvrrpd_sched_unset()
459 | {
460 | #ifdef _POSIX_PRIORITY_SCHEDULING
461 | struct sched_param param;
462 |
463 | param.sched_priority = sched_get_priority_max(SCHED_OTHER);
464 | if (sched_setscheduler(0, SCHED_OTHER, ¶m) != 0) {
465 | log_error("sched_setscheduler() - %m");
466 | return -1;
467 | }
468 | #endif
469 | return 0;
470 | }
471 |
--------------------------------------------------------------------------------
/uvrrpd.h:
--------------------------------------------------------------------------------
1 | /*
2 | * uvrrpd.h
3 | *
4 | * Copyright (C) 2014 Arnaud Andre
5 | *
6 | * This file is part of uvrrpd.
7 | *
8 | * uvrrpd is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU General Public License as published by
10 | * the Free Software Foundation, either version 3 of the License, or
11 | * (at your option) any later version.
12 | *
13 | * uvrrpd is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU General Public License
19 | * along with uvrrpd. If not, see .
20 | */
21 |
22 | #ifndef _UVRRPD_H_
23 | #define _UVRRPD_H_
24 |
25 | #include "bits.h"
26 |
27 | #define PIDFILE_NAME stringify(PATHRUN) "/uvrrpd_%d.pid"
28 | #define CTRLFILE_NAME stringify(PATHRUN) "/uvrrpd_ctrl.%d"
29 |
30 | /**
31 | * uvrrpd_control
32 | * Enum server control register flags
33 | */
34 | enum uvrrpd_control {
35 | /* daemon keep going bit */
36 | KEEP_GOING = BIT_MASK(0),
37 | /* daemon dump bit */
38 | UVRRPD_DUMP = BIT_MASK(1),
39 | /* daemon logout bit */
40 | UVRRPD_LOGOUT = BIT_MASK(2),
41 | /* daemon reload bit */
42 | UVRRPD_RELOAD = BIT_MASK(3),
43 | };
44 |
45 | int uvrrpd_sched_set(void);
46 | int uvrrpd_sched_unset(void);
47 |
48 | #endif /* _UVRRPD_ */
49 |
--------------------------------------------------------------------------------
/vrrp.c:
--------------------------------------------------------------------------------
1 | /*
2 | * vrrp.c - init VRRP instance and VRRP state functions
3 | *
4 | * Copyright (C) 2014 Arnaud Andre
5 | *
6 | * This file is part of uvrrpd.
7 | *
8 | * uvrrpd is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU General Public License as published by
10 | * the Free Software Foundation, either version 3 of the License, or
11 | * (at your option) any later version.
12 | *
13 | * uvrrpd is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU General Public License
19 | * along with uvrrpd. If not, see .
20 | */
21 |
22 | #include
23 | /* pselect() */
24 | #include
25 | #include
26 |
27 | #include "vrrp.h"
28 | #include "vrrp_timer.h"
29 | #include "vrrp_net.h"
30 | #include "vrrp_state.h"
31 | #include "vrrp_ctrl.h"
32 |
33 | #include "uvrrpd.h"
34 | #include "bits.h"
35 |
36 | #include "log.h"
37 |
38 | extern unsigned long reg;
39 |
40 | /**
41 | * vrrp_init() - init struct vrrp with default values
42 | */
43 | void vrrp_init(struct vrrp *vrrp)
44 | {
45 | /* VRRP version */
46 | vrrp->version = RFC3768;
47 |
48 | vrrp->vrid = 0;
49 | vrrp->priority = PRIO_DFL;
50 | vrrp->naddr = 0;
51 |
52 | /* auth */
53 | vrrp->auth_type = NOAUTH;
54 | vrrp->auth_data = NULL;
55 |
56 | /* state */
57 | vrrp->state = INIT;
58 | vrrp->preempt = PREEMPT_DFL;
59 |
60 | /* script */
61 | vrrp->scriptname = NULL;
62 | vrrp->argv = NULL;
63 |
64 | /* timers */
65 | vrrp->adv_int = 0;
66 | vrrp->start_delay = 0;
67 | vrrp->master_adv_int = 0;
68 | vrrp_timer_clear(&vrrp->adv_timer);
69 | vrrp_timer_clear(&vrrp->masterdown_timer);
70 | }
71 |
72 | /**
73 | * vrrp_context() - dump vrrp info
74 | */
75 | static void vrrp_context(struct vrrp *vrrp)
76 | {
77 | log_notice("====================");
78 | log_notice("VRID %d", vrrp->vrid);
79 | log_notice("current_state %s", STR_STATE(vrrp->state));
80 | log_notice("priority %d", vrrp->priority);
81 | log_notice("adv_int %d", vrrp->adv_int);
82 | if (vrrp->version == RFC5798)
83 | log_notice("master_adv_int %d", vrrp->master_adv_int);
84 | log_notice("preempt %s", STR_PREEMPT(vrrp->preempt));
85 | log_notice("naddr %d", vrrp->naddr);
86 | log_notice("====================");
87 | }
88 |
89 |
90 | /**
91 | * vrrp_process() - vrrp control and state machine
92 | */
93 | int vrrp_process(struct vrrp *vrrp, struct vrrp_net *vnet)
94 | {
95 | switch (vrrp->state) {
96 | case INIT:
97 | vrrp_state_init(vrrp, vnet);
98 | break;
99 |
100 | case BACKUP:
101 | vrrp_state_backup(vrrp, vnet);
102 | break;
103 |
104 | case MASTER:
105 | vrrp_state_master(vrrp, vnet);
106 | break;
107 |
108 | default:
109 | /* invalid state */
110 | return -ENOSYS;
111 | break;
112 | }
113 |
114 | if (test_and_clear_bit(UVRRPD_DUMP, ®))
115 | vrrp_context(vrrp);
116 |
117 | return 0;
118 | }
119 |
120 | /**
121 | * vrrp_listen() - Wait for a event (VRRP pkt, msg on fifo ...)
122 | *
123 | * @return vrrp_event_t
124 | * TIMER if current timer is expired
125 | * another event else
126 | */
127 | vrrp_event_t vrrp_listen(struct vrrp *vrrp, struct vrrp_net *vnet)
128 | {
129 | struct vrrp_timer *vt;
130 | int max_fd;
131 |
132 | /* Check which timer is running
133 | * Advertisement timer or Masterdown timer ?
134 | */
135 | if (vrrp_timer_is_running(&vrrp->adv_timer)) {
136 | log_debug("vrid %d :: adv_timer is running", vrrp->vrid);
137 | vt = &vrrp->adv_timer;
138 | }
139 | else if (vrrp_timer_is_running(&vrrp->masterdown_timer)) {
140 | log_debug("vrid %d :: masterdown_timer is running", vrrp->vrid);
141 | vt = &vrrp->masterdown_timer;
142 | }
143 | else { /* No timer ? ... exit */
144 | log_error("vrid %d :: no timer running !", vrrp->vrid);
145 | /* TODO die() */
146 | exit(EXIT_FAILURE);
147 | }
148 |
149 | /* update timer before pselect() */
150 | if (vrrp_timer_update(vt)) {
151 | log_debug("vrid %d :: timer expired before pselect",
152 | vrrp->vrid);
153 | /* timer expired or invalid */
154 | return TIMER;
155 | }
156 |
157 | /* pselect */
158 | fd_set readfds;
159 | FD_ZERO(&readfds);
160 | FD_SET(vnet->socket, &readfds);
161 | FD_SET(vrrp->ctrl.fd, &readfds);
162 | max_fd = max(vnet->socket, vrrp->ctrl.fd);
163 |
164 | sigset_t emptyset;
165 | sigemptyset(&emptyset);
166 |
167 | /* Wait for packet or timer expiration */
168 | if (pselect
169 | (max_fd + 1, &readfds, NULL, NULL,
170 | (const struct timespec *) &vt->delta, &emptyset) >= 0) {
171 |
172 |
173 | /* Timer is expired */
174 | if (vrrp_timer_is_expired(vt)) {
175 | log_debug("vrid %d :: timer expired", vrrp->vrid);
176 | return TIMER;
177 | }
178 |
179 | /* Else we have received a pkt */
180 | log_debug("vrid %d :: VRRP pkt received", vrrp->vrid);
181 |
182 | if (FD_ISSET(vnet->socket, &readfds))
183 | /* check if received is valid or not */
184 | return vrrp_net_recv(vnet, vrrp);
185 |
186 | if (FD_ISSET(vrrp->ctrl.fd, &readfds)) {
187 | return vrrp_ctrl_read(vrrp, vnet);
188 | }
189 | }
190 | else { /* Signal or pselect error */
191 | if (errno == EINTR) {
192 | log_debug("vrid %d :: signal caught", vrrp->vrid);
193 |
194 | return SIGNAL;
195 | }
196 |
197 | log_error("vrid %d :: pselect - %m", vrrp->vrid);
198 | }
199 |
200 | return INVALID;
201 | }
202 |
203 |
204 | /**
205 | * vrrp_cleanup() - clean before exiting
206 | */
207 | void vrrp_cleanup(struct vrrp *vrrp)
208 | {
209 | free(vrrp->scriptname);
210 | free(vrrp->auth_data);
211 | }
212 |
--------------------------------------------------------------------------------
/vrrp.h:
--------------------------------------------------------------------------------
1 | /*
2 | * vrrp.h - define main struct vrrp (VRRP instance) and some
3 | * constants
4 | *
5 | * Copyright (C) 2014 Arnaud Andre
6 | *
7 | * This file is part of uvrrpd.
8 | *
9 | * uvrrpd is free software: you can redistribute it and/or modify
10 | * it under the terms of the GNU General Public License as published by
11 | * the Free Software Foundation, either version 3 of the License, or
12 | * (at your option) any later version.
13 | *
14 | * uvrrpd is distributed in the hope that it will be useful,
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | * GNU General Public License for more details.
18 | *
19 | * You should have received a copy of the GNU General Public License
20 | * along with uvrrpd. If not, see .
21 | */
22 |
23 | #ifndef _VRRP_H_
24 | #define _VRRP_H_
25 |
26 | #include
27 |
28 | #include "common.h"
29 | #include "vrrp_net.h"
30 | #include "vrrp_timer.h"
31 | #include "vrrp_state.h"
32 | #include "vrrp_ctrl.h"
33 |
34 | /* MAX values */
35 | #define VRID_MAX 255
36 | #define VRRP_PRIO_MAX 255
37 | #define ADVINT_MAX 4095 /* RFC5798 */
38 | #define PRIO_OWNER VRRP_PRIO_MAX
39 |
40 | /* DEFAULT values */
41 | #define PREEMPT_DFL TRUE
42 | #define PRIO_DFL 100
43 |
44 | /* External script */
45 | #define VRRP_SCRIPT stringify(PATH) "/vrrp_switch.sh"
46 | #define VRRP_SCRIPT_MAX sysconf(_SC_ARG_MAX)
47 |
48 | /* preemption */
49 | #define STR_PREEMPT(s) (s == TRUE ? "true" : "false")
50 |
51 | /**
52 | * vrrp_version - VRRP version protocol
53 | * @RFC2338 : VRRPv2 (deprecated)
54 | * @RFC3768 : VRRPv2
55 | * @RFC5798 : VRRPv3
56 | */
57 | typedef enum {
58 | RFC2338 = 2,
59 | RFC3768 = 2,
60 | RFC5798 = 3
61 | } vrrp_version;
62 |
63 | /**
64 | * vrrp_authtype - Authentication type
65 | * (from VRRPv2 / rfc2332)
66 | */
67 | #define VRRP_AUTH_PASS_LEN 8
68 | typedef enum {
69 | NOAUTH,
70 | SIMPLE,
71 | HMAC /* not supported */
72 | } vrrp_authtype;
73 |
74 | /**
75 | * vrrp - Main structure defining VRRP instance
76 | */
77 | struct vrrp {
78 | vrrp_version version; /* VRRP version */
79 | uint8_t vrid; /* VRID 1 - 255 */
80 | uint8_t priority; /* PRIO 0 - 255 */
81 | uint8_t naddr; /* count ip addresses */
82 |
83 | /* Advertisement interval
84 | *
85 | * VRRPv2 :
86 | * - delay in s
87 | * - default 1s
88 | * - 8 bits field
89 | *
90 | * VRRPv3 :
91 | * - delay in centisecond
92 | * - default 100cs (1s)
93 | * - 12 bits field
94 | */
95 | uint16_t adv_int;
96 |
97 | /* Start delay */
98 | uint16_t start_delay;
99 |
100 | /* Master advertisement interval
101 | * only in VRRPv3 / rfc5798
102 | */
103 | uint16_t master_adv_int;
104 |
105 | vrrp_authtype auth_type;
106 | char *auth_data;
107 |
108 | vrrp_state state;
109 | bool preempt;
110 |
111 | char *scriptname;
112 | char **argv;
113 |
114 | /* control cmd fifo */
115 | struct vrrp_ctrl ctrl;
116 |
117 | struct vrrp_timer adv_timer;
118 | struct vrrp_timer masterdown_timer;
119 | };
120 |
121 | /**
122 | * enum vrrp_ret - Return code used in vrrp_net_listen
123 | */
124 | enum _vrrp_event_type {
125 | VRID_MISMATCH = -2, /* vrid mismatch */
126 | INVALID = -1, /* invalid pkt */
127 | PKT, /* valid packet */
128 | SIGNAL, /* signal catch */
129 | CTRL_FIFO, /* ctrl cmd event */
130 | TIMER /* timer expired */
131 | };
132 |
133 | typedef enum _vrrp_event_type vrrp_event_t;
134 | /* funcs */
135 | void vrrp_init(struct vrrp *vrrp);
136 | void vrrp_cleanup(struct vrrp *vrrp);
137 | int vrrp_process(struct vrrp *vrrp, struct vrrp_net *vnet);
138 | vrrp_event_t vrrp_listen(struct vrrp *vrrp, struct vrrp_net *vnet);
139 |
140 | #endif /* _VRRP_H_ */
141 |
--------------------------------------------------------------------------------
/vrrp_adv.c:
--------------------------------------------------------------------------------
1 | /*
2 | * vrrp_adv.c - VRRP advertisement
3 | *
4 | * Copyright (C) 2014 Arnaud Andre
5 | *
6 | * This file is part of uvrrpd.
7 | *
8 | * uvrrpd is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU General Public License as published by
10 | * the Free Software Foundation, either version 3 of the License, or
11 | * (at your option) any later version.
12 | *
13 | * uvrrpd is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU General Public License
19 | * along with uvrrpd. If not, see .
20 | */
21 |
22 | #include
23 | #include
24 | #include
25 | #include // ETH_P_IP = 0x0800, ETH_P_IPV6 = 0x86DD
26 | #include
27 | #include
28 | #ifdef HAVE_IP6
29 | #include
30 | #endif
31 |
32 | #include "log.h"
33 | #include "vrrp.h"
34 | #include "vrrp_net.h"
35 | #include "vrrp_rfc.h"
36 |
37 | /* VRRP multicast group */
38 | #define INADDR_VRRP_GROUP 0xe0000012 /* 224.0.0.18 */
39 |
40 | #ifdef HAVE_IP6
41 | #define IN6ADDR_VRRP_GROUP "FF02::12"
42 | #endif
43 |
44 | #define ETHDR_SIZE sizeof(struct ether_header)
45 |
46 | #define VRRP_TYPE_ADV 1
47 |
48 | /**
49 | * ether_header vrrp_adv_eth - VRRP ethernet header
50 | */
51 | static struct ether_header vrrp_adv_eth = {
52 | .ether_dhost = {0x01,
53 | 0x00,
54 | 0x5e,
55 | (INADDR_VRRP_GROUP >> 16) & 0x7F,
56 | (INADDR_VRRP_GROUP >> 8) & 0xFF,
57 | INADDR_VRRP_GROUP & 0xFF},
58 | .ether_shost = {0x00,
59 | 0x00,
60 | 0x5e,
61 | 0x00,
62 | 0x01,
63 | 0x00}, /* vrrp->vrid */
64 | };
65 |
66 | /**
67 | * vrrp_adv_eth_build() - build VRRP adv ethernet header
68 | */
69 | static int vrrp_adv_eth_build(struct iovec *iov, const uint8_t vrid,
70 | const int family)
71 | {
72 | iov->iov_base = malloc(sizeof(struct ether_header));
73 | struct ether_header *hdr = iov->iov_base;
74 |
75 | if (hdr == NULL) {
76 | log_error("vrid %d :: malloc - %m", vrid);
77 | return -1;
78 | }
79 |
80 | memcpy(hdr, &vrrp_adv_eth, sizeof(struct ether_header));
81 | hdr->ether_shost[5] = vrid;
82 | if (family == AF_INET)
83 | hdr->ether_type = htons(ETH_P_IP);
84 | #ifdef HAVE_IP6
85 | else /* AF_INET6 */
86 | hdr->ether_type = htons(ETH_P_IPV6);
87 | #endif
88 | iov->iov_len = ETHDR_SIZE;
89 |
90 | return 0;
91 | }
92 |
93 | /**
94 | * vrrp_adv_ip4_build() - build VRRP IPv4 advertisement
95 | */
96 | static int vrrp_adv_ip4_build(struct iovec *iov, const struct vrrp_net *vnet)
97 | {
98 | iov->iov_base = malloc(sizeof(struct iphdr));
99 |
100 | struct iphdr *iph = iov->iov_base;
101 |
102 | if (iph == NULL) {
103 | log_error("vrid %d :: malloc - %m", vnet->vrid);
104 | return -1;
105 | }
106 |
107 | iph->ihl = 0x5;
108 | iph->version = IPVERSION;
109 | iph->tos = 0x00;
110 | iph->tot_len = htons(IPHDR_SIZE + vnet->adv_getsize(vnet));
111 | iph->id = htons(0xdead);
112 | iph->ttl = 0xff; /* VRRP_TTL */
113 | iph->frag_off = 0x00;
114 | iph->protocol = IPPROTO_VRRP;
115 |
116 | iph->saddr = vnet->vif.ip_addr.s_addr;
117 | iph->daddr = htonl(INADDR_VRRP_GROUP);
118 |
119 | iph->check = 0;
120 | iph->check = cksum((unsigned short *) iph, IPHDR_SIZE);
121 |
122 | iov->iov_len = IPHDR_SIZE;
123 |
124 | return 0;
125 | }
126 |
127 | /**
128 | * vrrp_adv_ip6_build() - build VRRP IPv6 advertisement
129 | */
130 | #ifdef HAVE_IP6
131 | static int vrrp_adv_ip6_build(struct iovec *iov, const struct vrrp_net *vnet)
132 | {
133 | iov->iov_base = malloc(sizeof(struct ip6_hdr));
134 |
135 | struct ip6_hdr *ip6h = iov->iov_base;
136 |
137 | if (ip6h == NULL) {
138 | log_error("vrid %d :: malloc - %m", vnet->vrid);
139 | return -1;
140 | }
141 |
142 | ip6h->ip6_flow = htonl((6 << 28) | (0 << 20) | 0);
143 | ip6h->ip6_plen = htons(vnet->adv_getsize(vnet));
144 | ip6h->ip6_nxt = IPPROTO_VRRP;
145 | ip6h->ip6_hlim = 0xff; /* VRRP_TTL */
146 |
147 | memcpy(&ip6h->ip6_src, &vnet->vif.ip_addr6, sizeof(struct in6_addr));
148 |
149 | if (inet_pton(AF_INET6, IN6ADDR_VRRP_GROUP, &(ip6h->ip6_dst)) != 1) {
150 | log_error("vrid %d :: inet_pton - %m", vnet->vrid);
151 | return -1;
152 | }
153 |
154 | iov->iov_len = sizeof(struct ip6_hdr);
155 |
156 | return 0;
157 | }
158 | #endif /* HAVE_IP6 */
159 |
160 | /**
161 | * vrrp_net_adv_build() - build VRRP adv pkt
162 | */
163 | static int vrrp_adv_build(struct iovec *iov, const struct vrrp_net *vnet,
164 | const struct vrrp *vrrp)
165 | {
166 | iov->iov_base = malloc(vnet->adv_getsize(vnet));
167 |
168 | struct vrrphdr *pkt = iov->iov_base;
169 |
170 | if (pkt == NULL) {
171 | log_error("vrid %d :: malloc - %m", vnet->vrid);
172 | return -1;
173 | }
174 |
175 | pkt->version_type = (vrrp->version << 4) | VRRP_TYPE_ADV;
176 | pkt->vrid = vnet->vrid;
177 | pkt->priority = vrrp->priority;
178 | pkt->naddr = vrrp->naddr;
179 |
180 | if (vrrp->version == RFC3768) {
181 | pkt->auth_type = vrrp->auth_type;
182 | pkt->adv_int = vrrp->adv_int;
183 | }
184 | else if (vrrp->version == RFC5798) {
185 | pkt->max_adv_int = htons(vrrp->adv_int);
186 | }
187 |
188 | /* write vrrp_ip addresses */
189 | uint32_t *vip_addr =
190 | (uint32_t *) ((unsigned char *) pkt + VRRP_PKTHDR_SIZE);
191 |
192 | struct vrrp_ip *vip_ptr = NULL;
193 | uint32_t pos = 0;
194 | int naddr = 0;
195 |
196 | list_for_each_entry_reverse(vip_ptr, &vnet->vip_list, iplist) {
197 |
198 | if (vnet->family == AF_INET) {
199 | vip_addr[pos] = vip_ptr->ip_addr.s_addr;
200 | ++pos;
201 | }
202 | #ifdef HAVE_IP6
203 | else { /* AF_INET6 */
204 | memcpy(&vip_addr[pos], &vip_ptr->ip_addr6,
205 | sizeof(struct in6_addr));
206 | pos += 4;
207 | }
208 | #endif /* HAVE_IP6 */
209 | ++naddr;
210 |
211 | if (naddr > vrrp->naddr) {
212 | log_error
213 | ("vrid %d :: Build invalid avd pkt, try to write more vip than expected",
214 | vnet->vrid);
215 | return -1;
216 | }
217 | };
218 |
219 | /* auth password */
220 | if ((vrrp->version == RFC2338) && (vrrp->auth_type == SIMPLE)
221 | && (vrrp->auth_data != NULL)) {
222 | uint32_t *auth_data = vip_addr + pos;
223 | memcpy(auth_data, vrrp->auth_data, strlen(vrrp->auth_data));
224 | }
225 |
226 | /* chksum */
227 | pkt->chksum = vnet->adv_checksum(vnet, pkt, NULL, NULL);
228 |
229 | /* iov_len */
230 | iov->iov_len = vnet->adv_getsize(vnet);
231 |
232 | return 0;
233 | }
234 |
235 | /**
236 | * vrrp_adv_send() - send VRRP adv pkt
237 | */
238 | int vrrp_adv_send(struct vrrp_net *vnet)
239 | {
240 | return vrrp_net_send(vnet, vnet->__adv, ARRAY_SIZE(vnet->__adv));
241 | }
242 |
243 | /**
244 | * vrrp_adv_send_zero() - send VRRP adv pkt with priority 0
245 | */
246 | int vrrp_adv_send_zero(struct vrrp_net *vnet)
247 | {
248 | /* get adv buffer */
249 | struct iovec *iov = &vnet->__adv[2];
250 | struct vrrphdr *pkt = iov->iov_base;
251 |
252 | /* set priority to 0 and recompute checksum */
253 | uint8_t priority = pkt->priority;
254 | pkt->priority = 0;
255 | uint16_t chksum = pkt->chksum;
256 |
257 | /* chksum */
258 | pkt->chksum = vnet->adv_checksum(vnet, pkt, NULL, NULL);
259 |
260 | /* send adv pkt */
261 | int ret = vrrp_net_send(vnet, vnet->__adv, ARRAY_SIZE(vnet->__adv));
262 |
263 | /* restaure original priority and checksum */
264 | pkt->priority = priority;
265 | pkt->chksum = chksum;
266 |
267 | return ret;
268 | }
269 |
270 | /**
271 | * vrrp_adv_init() - init advertisement pkt to send
272 | */
273 | int vrrp_adv_init(struct vrrp_net *vnet, const struct vrrp *vrrp)
274 | {
275 | int status = -1;
276 |
277 | status = vrrp_adv_eth_build(&vnet->__adv[0], vnet->vrid, vnet->family);
278 |
279 | if (vnet->family == AF_INET)
280 | status |= vrrp_adv_ip4_build(&vnet->__adv[1], vnet);
281 | #ifdef HAVE_IP6
282 | else /* AF_INET6 */
283 | status |= vrrp_adv_ip6_build(&vnet->__adv[1], vnet);
284 | #endif /* HAVE_IP6 */
285 |
286 | status |= vrrp_adv_build(&vnet->__adv[2], vnet, vrrp);
287 |
288 | return status;
289 | }
290 |
291 | /**
292 | * vrrp_adv_cleanup()
293 | */
294 | void vrrp_adv_cleanup(struct vrrp_net *vnet)
295 | {
296 | /* clean iovec */
297 | for (int i = 0; i < 3; ++i) {
298 | struct iovec *iov = &vnet->__adv[i];
299 | free(iov->iov_base);
300 | }
301 | }
302 |
--------------------------------------------------------------------------------
/vrrp_adv.h:
--------------------------------------------------------------------------------
1 | /*
2 | * vrrp_adv.h - VRRP advertisement
3 | *
4 | * Copyright (C) 2014 Arnaud Andre
5 | *
6 | * This file is part of uvrrpd.
7 | *
8 | * uvrrpd is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU General Public License as published by
10 | * the Free Software Foundation, either version 3 of the License, or
11 | * (at your option) any later version.
12 | *
13 | * uvrrpd is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU General Public License
19 | * along with uvrrpd. If not, see .
20 | */
21 |
22 | #ifndef _VRRP_ADV_H_
23 | #define _VRRP_ADV_H_
24 |
25 |
26 | int vrrp_adv_init(struct vrrp_net *vnet, const struct vrrp *vrrp);
27 | void vrrp_adv_cleanup(struct vrrp_net *vnet);
28 | int vrrp_adv_send(struct vrrp_net *vnet);
29 | int vrrp_adv_send_zero(struct vrrp_net *vnet);
30 | uint16_t vrrp_adv_chksum(struct vrrp_net *vnet, struct vrrphdr *pkt,
31 | uint32_t saddr, uint32_t daddr);
32 | #ifdef HAVE_IP6
33 | uint16_t vrrp_adv_ip6_chksum(struct vrrp_net *vnet, struct vrrphdr *pkt,
34 | struct in6_addr *saddr, struct in6_addr *daddr);
35 | #endif /* HAVE_IP6 */
36 |
37 | /**
38 | * vrrp_adv_get_version() - get version_type from received adv pkt
39 | */
40 | static inline int vrrp_adv_get_version(const struct vrrp_net *vnet)
41 | {
42 | return vnet->__pkt.adv.version_type;
43 | }
44 |
45 | /**
46 | * vrrp_adv_get_priority() - get priority from received adv priority
47 | */
48 | static inline int vrrp_adv_get_priority(const struct vrrp_net *vnet)
49 | {
50 | return vnet->__pkt.adv.priority;
51 | }
52 |
53 | /**
54 | * vrrp_adv_set_priority() - set priority in emitted adv pkt
55 | */
56 | static inline void vrrp_adv_set_priority(struct vrrp_net *vnet, uint8_t prio)
57 | {
58 | struct vrrphdr *pkt = vnet->__adv[2].iov_base;
59 | pkt->priority = prio;
60 |
61 | /* recompute chksum */
62 | pkt->chksum = vnet->adv_checksum(vnet, pkt, NULL, NULL);
63 |
64 | log_notice("vrid %d :: new prio %d applied", vnet->vrid, pkt->priority);
65 | }
66 |
67 | /**
68 | * vrrp_adv_addr_to_str() - return source ip from received adv pkt
69 | * in string format
70 | */
71 | static inline const char *vrrp_adv_addr_to_str(struct vrrp_net *vnet, char *dst)
72 | {
73 | return vnet->ipx_to_str(&vnet->__pkt.s_ipx, dst);
74 | }
75 |
76 | /**
77 | * vrrp_adv_get_compare() - compare received adv pkt addr to local
78 | * primary address
79 | */
80 | static inline int vrrp_adv_addr_cmp(struct vrrp_net *vnet)
81 | {
82 | return vnet->ipx_cmp(&vnet->__pkt.s_ipx, &vnet->vif.ipx);
83 | }
84 |
85 | /**
86 | * vrrp_adv_get_advint() - get adv interval
87 | */
88 | static inline uint16_t vrrp_adv_get_advint(const struct vrrp_net *vnet)
89 | {
90 | if (vnet->__pkt.adv.version_type >> 4 == RFC5798)
91 | return ntohs(vnet->__pkt.adv.max_adv_int);
92 |
93 | return vnet->__pkt.adv.adv_int;
94 |
95 | }
96 | #endif /* _VRRP_ADV_H_ */
97 |
--------------------------------------------------------------------------------
/vrrp_arp.c:
--------------------------------------------------------------------------------
1 | /*
2 | * vrrp_arp.c
3 | *
4 | * Copyright (C) 2014 Arnaud Andre
5 | *
6 | * This file is part of uvrrpd.
7 | *
8 | * uvrrpd is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU General Public License as published by
10 | * the Free Software Foundation, either version 3 of the License, or
11 | * (at your option) any later version.
12 | *
13 | * uvrrpd is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU General Public License
19 | * along with uvrrpd. If not, see .
20 | */
21 |
22 | #include
23 | #include
24 | #include
25 | #include // ETH_P_IP = 0x0800, ETH_P_IPV6 = 0x86DD
26 | #include
27 | #include
28 | #include
29 |
30 | #include "log.h"
31 | #include "vrrp.h"
32 | #include "vrrp_net.h"
33 |
34 | #define ETHDR_SIZE sizeof(struct ether_header)
35 |
36 | /**
37 | * ether_header vrrp_arp_eth
38 | */
39 | static struct ether_header vrrp_arp_eth = {
40 | .ether_dhost = {0xff, 0xff, 0xff,
41 | 0xff, 0xff, 0xff},
42 | .ether_shost = {0x00,
43 | 0x00,
44 | 0x5e,
45 | 0x00,
46 | 0x01,
47 | 0x00}, /* vrrp->vrid */
48 | };
49 |
50 |
51 | #define IP_ALEN 4
52 | /**
53 | * arphdr_eth - ARP header
54 | */
55 | struct arphdr_eth {
56 | unsigned char ar_sha[ETH_ALEN]; /* Sender hardware address */
57 | unsigned char ar_sip[IP_ALEN]; /* Sender IP address */
58 | unsigned char ar_tha[ETH_ALEN]; /* Target hardware address */
59 | unsigned char ar_tip[IP_ALEN]; /* Target IP address */
60 | };
61 |
62 |
63 | /**
64 | * vrrp_arp_eth_build()
65 | */
66 | static int vrrp_arp_eth_build(struct iovec *iov, const uint8_t vrid)
67 | {
68 | iov->iov_base = malloc(sizeof(struct ether_header));
69 |
70 | struct ether_header *hdr = iov->iov_base;
71 |
72 | if (hdr == NULL) {
73 | log_error("vrid %d :: malloc - %m", vrid);
74 | return -1;
75 | }
76 |
77 | memcpy(hdr, &vrrp_arp_eth, sizeof(struct ether_header));
78 |
79 | hdr->ether_shost[5] = vrid;
80 | hdr->ether_type = htons(ETHERTYPE_ARP);
81 |
82 | iov->iov_len = ETHDR_SIZE;
83 |
84 | return 0;
85 | }
86 |
87 | /**
88 | * vrrp_arp_send() - Send arp gratuitous for each vip
89 | */
90 | int vrrp_arp_send(struct vrrp_net *vnet)
91 | {
92 | struct vrrp_ip *vip_ptr = NULL;
93 |
94 | /* we have to send one arp pkt by vip */
95 | list_for_each_entry_reverse(vip_ptr, &vnet->vip_list, iplist) {
96 | vrrp_net_send(vnet, vip_ptr->__topology,
97 | ARRAY_SIZE(vip_ptr->__topology));
98 | }
99 |
100 | return 0;
101 | }
102 |
103 | /**
104 | * vrrp_arp_build() - Build arp header
105 | */
106 | static int vrrp_arp_build(struct iovec *iov, const uint8_t vrid)
107 | {
108 | iov->iov_base = malloc(sizeof(struct arphdr));
109 |
110 | struct arphdr *arph = iov->iov_base;
111 |
112 | if (arph == NULL) {
113 | log_error("vrid %d :: malloc - %m", vrid);
114 | return -1;
115 | }
116 |
117 | arph->ar_hrd = htons(ARPHRD_ETHER); /* Format of hardware address */
118 | arph->ar_pro = htons(ETHERTYPE_IP); /* Format of protocol address */
119 | arph->ar_hln = ETH_ALEN; /* Length of hardware address */
120 | arph->ar_pln = IP_ALEN; /* Length of protocol address */
121 | arph->ar_op = htons(ARPOP_REQUEST); /* ARP opcode (command) */
122 |
123 | iov->iov_len = sizeof(struct arphdr);
124 |
125 | return 0;
126 | }
127 |
128 | /**
129 | * vrrp_arp_vrrp_build() - VRRP arp payload
130 | */
131 | static int vrrp_arp_vrrp_build(struct iovec *iov, struct vrrp_ip *vip,
132 | struct vrrp_net *vnet)
133 | {
134 | iov->iov_base = malloc(sizeof(struct arphdr_eth));
135 |
136 | struct arphdr_eth *arpeth = iov->iov_base;
137 |
138 | if (arpeth == NULL) {
139 | log_error("vrid %d :: malloc - %m", vnet->vrid);
140 | return -1;
141 | }
142 |
143 | arpeth->ar_sha[0] = 0x00;
144 | arpeth->ar_sha[1] = 0x00;
145 | arpeth->ar_sha[2] = 0x5e;
146 | arpeth->ar_sha[3] = 0x00;
147 | arpeth->ar_sha[4] = 0x01;
148 | arpeth->ar_sha[5] = vnet->vrid;
149 |
150 | memcpy(arpeth->ar_sip, &vip->ip_addr.s_addr, IP_ALEN);
151 | memset(arpeth->ar_tha, 0xFF, ETH_ALEN);
152 | memcpy(arpeth->ar_tip, &arpeth->ar_sip, IP_ALEN);
153 |
154 | iov->iov_len = sizeof(struct arphdr_eth);
155 |
156 | return 0;
157 | }
158 |
159 | /**
160 | * vrrp_arp_init()
161 | */
162 | int vrrp_arp_init(struct vrrp_net *vnet)
163 | {
164 | int status = -1;
165 |
166 | /* we have to build one arp pkt by vip */
167 | struct vrrp_ip *vip_ptr = NULL;
168 |
169 | list_for_each_entry_reverse(vip_ptr, &vnet->vip_list, iplist) {
170 | status =
171 | vrrp_arp_eth_build(&vip_ptr->__topology[0], vnet->vrid);
172 | status |= vrrp_arp_build(&vip_ptr->__topology[1], vnet->vrid);
173 | status |=
174 | vrrp_arp_vrrp_build(&vip_ptr->__topology[2], vip_ptr, vnet);
175 | }
176 |
177 | return status;
178 | }
179 |
180 | /**
181 | * vrrp_arp_cleanup()
182 | */
183 | void vrrp_arp_cleanup(struct vrrp_net *vnet)
184 | {
185 | /* clean arp buffer for each vrrp_ip addr */
186 | struct vrrp_ip *vip_ptr = NULL;
187 |
188 | list_for_each_entry(vip_ptr, &vnet->vip_list, iplist) {
189 |
190 | /* clean iovec */
191 | for (int i = 0; i < 3; ++i) {
192 | struct iovec *iov = &vip_ptr->__topology[i];
193 | free(iov->iov_base);
194 | }
195 | }
196 | }
197 |
--------------------------------------------------------------------------------
/vrrp_arp.h:
--------------------------------------------------------------------------------
1 | /*
2 | * vrrp_arp.h - ARP for VRRP IPv4 advertisement
3 | *
4 | * Copyright (C) 2014 Arnaud Andre
5 | *
6 | * This file is part of uvrrpd.
7 | *
8 | * uvrrpd is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU General Public License as published by
10 | * the Free Software Foundation, either version 3 of the License, or
11 | * (at your option) any later version.
12 | *
13 | * uvrrpd is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU General Public License
19 | * along with uvrrpd. If not, see .
20 | */
21 |
22 | #ifndef _VRRP_ARP_H_
23 | #define _VRRP_ARP_H_
24 |
25 | int vrrp_arp_init(struct vrrp_net *vnet);
26 | void vrrp_arp_cleanup(struct vrrp_net *vnet);
27 | int vrrp_arp_send(struct vrrp_net *vnet);
28 |
29 | #endif /* _VRRP_ARP_H_ */
30 |
--------------------------------------------------------------------------------
/vrrp_ctrl.c:
--------------------------------------------------------------------------------
1 | /*
2 | * vrrp_ctrl.c - control fifo
3 | *
4 | * Copyright (C) 2016 Arnaud Andre
5 | *
6 | * This file is part of uvrrpd.
7 | *
8 | * uvrrpd is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU General Public License as published by
10 | * the Free Software Foundation, either version 3 of the License, or
11 | * (at your option) any later version.
12 | *
13 | * uvrrpd is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU General Public License
19 | * along with uvrrpd. If not, see .
20 | */
21 |
22 |
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 |
31 | #include "vrrp.h"
32 | #include "vrrp_ctrl.h"
33 | #include "vrrp_adv.h"
34 |
35 | #include "common.h"
36 | #include "uvrrpd.h"
37 | #include "bits.h"
38 | #include "log.h"
39 |
40 | extern unsigned long reg;
41 |
42 | static inline vrrp_event_t vrrp_ctrl_cmd(struct vrrp *vrrp,
43 | struct vrrp_net *vnet);
44 |
45 | /**
46 | * flush_fifo() - flush a fifo fd
47 | */
48 | #define BUFLUSH 2048
49 |
50 | static inline int flush_fifo(int fd)
51 | {
52 | ssize_t bytes;
53 | char buf[BUFLUSH];
54 |
55 | while (1) {
56 | bytes = read(fd, buf, sizeof(buf));
57 | if (bytes <= 0) {
58 | if (errno == EWOULDBLOCK) {
59 | return 0;
60 | }
61 | else {
62 | log_error("read - %m");
63 | return -1;
64 | }
65 | }
66 | }
67 | return 0;
68 | }
69 |
70 | /**
71 | * split_cmd() - split a *str in words separated by delim
72 | * Fill a *words_ptr[max_words] with ptr to each found word
73 | * words_ptr must be pre-allocated
74 | * @return nword, number of found word,
75 | * -1 if entry str or words_ptr NULL
76 | */
77 | static inline int split_cmd(char *str, char **words_ptr, int max_words,
78 | char *delim)
79 | {
80 | if ((str == NULL) || (words_ptr == NULL))
81 | return -1;
82 |
83 | int nword;
84 | for (nword = 0; nword < max_words; ++nword) {
85 | if (str != NULL) {
86 | while (isspace(*str))
87 | str++; /* trim whitespace */
88 | if (str[0] != '\0')
89 | words_ptr[nword] = strsep(&str, delim);
90 | }
91 |
92 | if (words_ptr[nword] == NULL)
93 | break;
94 | }
95 |
96 |
97 | return nword;
98 | }
99 |
100 | /**
101 | * vrrp_ctrl_init()
102 | */
103 | int vrrp_ctrl_init(struct vrrp_ctrl *ctrl)
104 | {
105 | ctrl->cmd = malloc(sizeof(char *) * CTRL_CMD_NTOKEN);
106 |
107 | if (ctrl->cmd == NULL) {
108 | log_error("init :: malloc - %m");
109 | return -1;
110 | }
111 |
112 | bzero(ctrl->msg, CTRL_MAXCHAR);
113 |
114 | return 0;
115 | }
116 |
117 |
118 | /**
119 | * vrrp_ctrl_cmd_flush() - Flush cmd
120 | */
121 | static inline void vrrp_ctrl_cmd_flush(struct vrrp_ctrl *ctrl)
122 | {
123 | if (ctrl == NULL)
124 | return;
125 |
126 | /* clean buff */
127 | for (int i = 0; i < CTRL_CMD_NTOKEN; ctrl->cmd[i++] = NULL);
128 | bzero(ctrl->msg, CTRL_MAXCHAR);
129 | }
130 |
131 | /**
132 | * vrrp_ctrl_cmd() - Interprete control fifo cmd
133 | */
134 | static inline vrrp_event_t vrrp_ctrl_cmd(struct vrrp *vrrp,
135 | struct vrrp_net *vnet)
136 | {
137 | int nword;
138 |
139 | nword =
140 | split_cmd(vrrp->ctrl.msg, vrrp->ctrl.cmd, CTRL_CMD_NTOKEN,
141 | WHITESPACE);
142 |
143 | if (nword == 0)
144 | return INVALID;
145 |
146 | /*
147 | * control cmd stop
148 | */
149 | if (matches(vrrp->ctrl.cmd[0], "stop")) {
150 | log_notice("vrid %d :: control cmd stop, exiting", vrrp->vrid);
151 | set_bit(UVRRPD_RELOAD, ®);
152 | clear_bit(KEEP_GOING, ®);
153 | vrrp_ctrl_cmd_flush(&vrrp->ctrl);
154 | return CTRL_FIFO;
155 | }
156 |
157 | /*
158 | * control cmd reload
159 | */
160 | if (matches(vrrp->ctrl.cmd[0], "reload")) {
161 | set_bit(UVRRPD_RELOAD, ®);
162 | vrrp_ctrl_cmd_flush(&vrrp->ctrl);
163 | return CTRL_FIFO;
164 | }
165 |
166 | /*
167 | * control cmd state || status
168 | */
169 | if (matches(vrrp->ctrl.cmd[0], "state")
170 | || matches(vrrp->ctrl.cmd[0], "status")) {
171 |
172 | set_bit(UVRRPD_DUMP, ®);
173 | vrrp_ctrl_cmd_flush(&vrrp->ctrl);
174 | return CTRL_FIFO;
175 | }
176 |
177 | /*
178 | * control cmd prio
179 | */
180 | if (matches(vrrp->ctrl.cmd[0], "prio")) {
181 | if (nword != 2) {
182 | log_error
183 | ("vrid %d :: invalid syntax, control cmd prio ",
184 | vrrp->vrid);
185 |
186 | vrrp_ctrl_cmd_flush(&vrrp->ctrl);
187 | return INVALID;
188 | }
189 |
190 | /* fetch priority */
191 | int err;
192 | unsigned long opt;
193 | err = mystrtoul(&opt, vrrp->ctrl.cmd[1], VRRP_PRIO_MAX);
194 |
195 | vrrp_ctrl_cmd_flush(&vrrp->ctrl);
196 |
197 | if (err == -ERANGE) {
198 | log_error
199 | ("vrid %d :: invalid control cmd prio, 0 < priority < 255",
200 | vrrp->vrid);
201 | return INVALID;
202 | }
203 |
204 | if (err == -EINVAL) {
205 | log_error
206 | ("vrid %d :: invalid control cmd prio, error parsing \"%s\" as a number",
207 | vrrp->vrid, vrrp->ctrl.cmd[1]);
208 | return INVALID;
209 | }
210 |
211 | /* change prio */
212 | if (vrrp->priority != (uint8_t) opt) {
213 | vrrp->priority = (uint8_t) opt;
214 | vrrp_adv_set_priority(vnet, vrrp->priority);
215 | }
216 |
217 | /* reload bit */
218 | set_bit(UVRRPD_RELOAD, ®);
219 |
220 | return CTRL_FIFO;
221 | }
222 |
223 | vrrp_ctrl_cmd_flush(&vrrp->ctrl);
224 |
225 | return INVALID;
226 | }
227 |
228 | /**
229 | * vrrp_ctrl_read() - Read control fifo
230 | */
231 | vrrp_event_t vrrp_ctrl_read(struct vrrp * vrrp, struct vrrp_net * vnet)
232 | {
233 | int readbytes = 0;
234 |
235 | readbytes = read(vrrp->ctrl.fd, vrrp->ctrl.msg, CTRL_MAXCHAR);
236 |
237 | if (readbytes > 0) {
238 | flush_fifo(vrrp->ctrl.fd);
239 | vrrp->ctrl.msg[CTRL_MAXCHAR - 1] = '\0';
240 | return vrrp_ctrl_cmd(vrrp, vnet);
241 | }
242 |
243 | return INVALID;
244 | }
245 |
246 |
247 | /**
248 | * vrrp_ctrl_cleanup()
249 | */
250 | void vrrp_ctrl_cleanup(struct vrrp_ctrl *ctrl)
251 | {
252 | free(ctrl->cmd);
253 | }
254 |
--------------------------------------------------------------------------------
/vrrp_ctrl.h:
--------------------------------------------------------------------------------
1 | /*
2 | * vrrp_ctrl.h - control fifo header
3 | *
4 | * Copyright (C) 2016 Arnaud Andre
5 | *
6 | * This file is part of uvrrpd.
7 | *
8 | * uvrrpd is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU General Public License as published by
10 | * the Free Software Foundation, either version 3 of the License, or
11 | * (at your option) any later version.
12 | *
13 | * uvrrpd is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU General Public License
19 | * along with uvrrpd. If not, see .
20 | */
21 |
22 | #ifndef _VRRP_CTRL_H_
23 | #define _VRRP_CTRL_H_
24 |
25 | #include
26 |
27 | /* from vrrp.h */
28 | struct vrrp;
29 | struct vrrp_net;
30 | typedef enum _vrrp_event_type vrrp_event_t;
31 |
32 | #define CTRL_MAXCHAR 64
33 | #define CTRL_CMD_NTOKEN 3
34 |
35 | /**
36 | * vrrp_ctrl - infos about control fifo
37 | */
38 | struct vrrp_ctrl {
39 | /* control fifo fd */
40 | int fd;
41 |
42 | /* control fifo msg */
43 | char msg[CTRL_MAXCHAR];
44 |
45 | /* reformated command */
46 | char **cmd;
47 | };
48 |
49 |
50 |
51 | int vrrp_ctrl_init(struct vrrp_ctrl *ctrl);
52 | void vrrp_ctrl_cleanup(struct vrrp_ctrl *ctrl);
53 | vrrp_event_t vrrp_ctrl_read(struct vrrp *vrrp, struct vrrp_net *vnet);
54 |
55 |
56 | #endif /* _VRRP_CTRL_H_ */
57 |
--------------------------------------------------------------------------------
/vrrp_exec.c:
--------------------------------------------------------------------------------
1 | /*
2 | * vrrp_exec.c - call an external script while changing state
3 | *
4 | * Copyright (C) 2014 Arnaud Andre
5 | *
6 | * This file is part of uvrrpd.
7 | *
8 | * uvrrpd is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU General Public License as published by
10 | * the Free Software Foundation, either version 3 of the License, or
11 | * (at your option) any later version.
12 | *
13 | * uvrrpd is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU General Public License
19 | * along with uvrrpd. If not, see .
20 | */
21 |
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 |
32 | #include "vrrp.h"
33 | #include "vrrp_exec.h"
34 | #include "uvrrpd.h"
35 | #include "common.h"
36 | #include "log.h"
37 |
38 | /* SCRIPT_ARG_MAX : bytes of args
39 | * (255 IPv6 addresses might be specified)
40 | * 1 IPv6 = 45 bytes in a string format
41 | */
42 | #define SCRIPT_ARG_MAX INET6_ADDRSTRLEN * NI_MAXHOST
43 | #define ADDRSTRLEN INET6_ADDRSTRLEN
44 | #define SCRIPT_NARGS 10
45 |
46 | /**
47 | * vrrp_build_args() - prepare args that will be passed to
48 | * external script
49 | *
50 | * Build a argv array destined to execve()
51 | */
52 | static int vrrp_build_args(const char *scriptname, char **argv,
53 | const struct vrrp *vrrp, const struct vrrp_net *vnet,
54 | vrrp_state state)
55 | {
56 | /* get basename from scriptname */
57 | char *name = strchr(scriptname, '/');
58 | if (name != NULL) {
59 | name++;
60 | snprintf(argv[0], SCRIPT_ARG_MAX, "%s", name);
61 | }
62 | else
63 | snprintf(argv[0], SCRIPT_ARG_MAX, "%s", scriptname);
64 |
65 | /* List of args passed to script :
66 | * 1. state
67 | * 2. vrid
68 | * 3. ifname
69 | * 4. priority
70 | * 5. adv_int
71 | * 6. naddr
72 | * 7. family
73 | * 8 & more. vipaddrs ...
74 | */
75 | snprintf(argv[1], SCRIPT_ARG_MAX, "%s", STR_STATE(state));
76 | snprintf(argv[2], SCRIPT_ARG_MAX, "%d", vrrp->vrid);
77 | snprintf(argv[3], SCRIPT_ARG_MAX, "%s", vnet->vif.ifname);
78 | snprintf(argv[4], SCRIPT_ARG_MAX, "%d", vrrp->priority);
79 | snprintf(argv[5], SCRIPT_ARG_MAX, "%d", vrrp->adv_int);
80 | snprintf(argv[6], SCRIPT_ARG_MAX, "%d", vrrp->naddr);
81 | snprintf(argv[7], SCRIPT_ARG_MAX, "%d",
82 | (vnet->family == AF_INET ? 4 : 6));
83 |
84 | /* serialize vipaddrs
85 | * ip0,ip1,...,ipn */
86 | int argv_ips = SCRIPT_NARGS - 2;
87 | memset(argv[argv_ips], 0, strlen(argv[argv_ips]));
88 | int plen = 0;
89 | struct vrrp_ip *vip_ptr = NULL;
90 | list_for_each_entry_reverse(vip_ptr, &vnet->vip_list, iplist) {
91 | plen = strlen(argv[argv_ips]);
92 | if (plen != 0)
93 | argv[argv_ips][plen] = ',';
94 |
95 | char straddr[ADDRSTRLEN];
96 | snprintf(argv[argv_ips] + strlen(argv[argv_ips]),
97 | SCRIPT_ARG_MAX - plen + 1, "%s",
98 | vnet->ipx_to_str(&vip_ptr->ipx, straddr));
99 | }
100 |
101 | /* the last elmt must be NULL */
102 | argv[SCRIPT_NARGS - 1] = NULL;
103 |
104 | return 0;
105 | }
106 |
107 | /**
108 | * vrrp_exec()
109 | */
110 | int vrrp_exec(struct vrrp *vrrp, const struct vrrp_net *vnet, vrrp_state state)
111 | {
112 | const char *scriptname;
113 |
114 | if (vrrp->scriptname == NULL)
115 | scriptname = VRRP_SCRIPT;
116 | else
117 | scriptname = vrrp->scriptname;
118 |
119 | if (!is_file_executable(scriptname)) {
120 | log_error("vrid %d :: File %s doesn't exist or is not executable",
121 | vrrp->vrid, scriptname);
122 | return -1;
123 | }
124 |
125 | vrrp_build_args(scriptname, vrrp->argv, vrrp, vnet, state);
126 |
127 | /* Sig gestion */
128 | sigset_t blockmask, origmask;
129 | struct sigaction sa_ignore, sa_origquit, sa_origint, sa_default;
130 |
131 | sigemptyset(&blockmask); /* Block SIGCHLD */
132 | sigaddset(&blockmask, SIGCHLD);
133 | sigprocmask(SIG_BLOCK, &blockmask, &origmask);
134 | sa_ignore.sa_handler = SIG_IGN; /* Ignore SIGINT and SIGQUIT */
135 | sa_ignore.sa_flags = 0;
136 | sigemptyset(&sa_ignore.sa_mask);
137 | sigaction(SIGINT, &sa_ignore, &sa_origint);
138 | sigaction(SIGQUIT, &sa_ignore, &sa_origquit);
139 |
140 | /* fork */
141 | uvrrpd_sched_unset(); /* remove SCHED_RR */
142 | pid_t child = fork();
143 | int status, savedErrno;
144 |
145 | if (child == -1) {
146 | log_error("vrid %d :: fork - %m", vrrp->vrid);
147 | vrrp_exec_cleanup(vrrp);
148 | return -1;
149 | }
150 |
151 | /* child */
152 | if (child == 0) {
153 | sa_default.sa_handler = SIG_DFL;
154 | sa_default.sa_flags = 0;
155 | sigemptyset(&sa_default.sa_mask);
156 | if (sa_origint.sa_handler != SIG_IGN)
157 | sigaction(SIGINT, &sa_default, NULL);
158 | if (sa_origquit.sa_handler != SIG_IGN)
159 | sigaction(SIGQUIT, &sa_default, NULL);
160 | sigprocmask(SIG_SETMASK, &origmask, NULL);
161 |
162 | /* execve */
163 | execve(scriptname, (char *const *) vrrp->argv, NULL);
164 |
165 | log_error("vrid %d :: execve - %m", vrrp->vrid);
166 | vrrp_exec_cleanup(vrrp);
167 | return -1;
168 | }
169 |
170 | /* parent */
171 | if (child > 0) {
172 |
173 | uvrrpd_sched_set(); /* restore SCHED_RR */
174 | while (waitpid(child, &status, 0) == -1) {
175 | if (errno != EINTR) { /* Error other than EINTR */
176 | log_error("vrid %d :: waitpid - %m", vrrp->vrid);
177 | status = -1;
178 | break; /* So exit loop */
179 | }
180 | }
181 | }
182 |
183 | /* Unblock SIGCHLD, restore dispositions of SIGINT and SIGQUIT */
184 | savedErrno = errno; /* The following may change 'errno' */
185 | sigprocmask(SIG_SETMASK, &origmask, NULL);
186 | sigaction(SIGINT, &sa_origint, NULL);
187 | sigaction(SIGQUIT, &sa_origquit, NULL);
188 | errno = savedErrno;
189 |
190 | return status;
191 | }
192 |
193 | /**
194 | * vrrp_exec_init() - init vrrp->argv buffer
195 | */
196 | int vrrp_exec_init(struct vrrp *vrrp)
197 | {
198 | vrrp->argv = malloc(sizeof(char *) * SCRIPT_NARGS);
199 |
200 | if (vrrp->argv == NULL) {
201 | log_error("vrid %d :: malloc - %m", vrrp->vrid);
202 | return -1;
203 | }
204 |
205 | for (int i = 0; i < SCRIPT_NARGS - 1; ++i) {
206 | vrrp->argv[i] = malloc(sizeof(char) * SCRIPT_ARG_MAX);
207 | if (vrrp->argv[i] == NULL) {
208 | log_error("vrid %d :: malloc - %m", vrrp->vrid);
209 | return -1;
210 | }
211 | bzero(vrrp->argv[i], sizeof(char) * SCRIPT_ARG_MAX);
212 | }
213 |
214 | return 0;
215 | }
216 |
217 | /**
218 | * vrrp_exec_cleanup() - cleanup vrrp->argv buffer
219 | */
220 | void vrrp_exec_cleanup(struct vrrp *vrrp)
221 | {
222 | if (vrrp->argv != NULL) {
223 | for (int i = 0; i < SCRIPT_NARGS - 1; ++i) {
224 | free(vrrp->argv[i]);
225 | vrrp->argv[i] = NULL;
226 | }
227 | free(vrrp->argv);
228 | vrrp->argv = NULL;
229 | }
230 | }
231 |
--------------------------------------------------------------------------------
/vrrp_exec.h:
--------------------------------------------------------------------------------
1 | /*
2 | * vrrp_exec.h - export prototype of vrrp_exec()
3 | *
4 | * Copyright (C) 2014 Arnaud Andre
5 | *
6 | * This file is part of uvrrpd.
7 | *
8 | * uvrrpd is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU General Public License as published by
10 | * the Free Software Foundation, either version 3 of the License, or
11 | * (at your option) any later version.
12 | *
13 | * uvrrpd is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU General Public License
19 | * along with uvrrpd. If not, see .
20 | */
21 |
22 | #ifndef _VRRP_EXEC_H_
23 | #define _VRRP_EXEC_H_
24 |
25 | #include "vrrp.h"
26 |
27 | int vrrp_exec(struct vrrp *vrrp, const struct vrrp_net *vnet, vrrp_state state);
28 | int vrrp_exec_init(struct vrrp *vrrp);
29 | void vrrp_exec_cleanup(struct vrrp *vrrp);
30 |
31 | #endif /* _VRRP_EXEC_H_ */
32 |
--------------------------------------------------------------------------------
/vrrp_ip4.c:
--------------------------------------------------------------------------------
1 | /*
2 | * vrrp_ip4.c - IP4 helpers functions
3 | *
4 | * Copyright (C) 2014 Arnaud Andre
5 | *
6 | * This file is part of uvrrpd.
7 | *
8 | * uvrrpd is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU General Public License as published by
10 | * the Free Software Foundation, either version 3 of the License, or
11 | * (at your option) any later version.
12 | *
13 | * uvrrpd is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU General Public License
19 | * along with uvrrpd. If not, see .
20 | */
21 |
22 |
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 | /* ifreq + ioctl */
33 | #include
34 | #include
35 | #include
36 | #include
37 |
38 | #include "vrrp.h"
39 | #include "vrrp_ipx.h"
40 | #include "vrrp_net.h"
41 | #include "vrrp_adv.h"
42 | #include "log.h"
43 | #include "common.h"
44 |
45 | #define VRRP_MGROUP4 "224.0.0.18"
46 |
47 | /**
48 | * pshdr_ip4 - pseudo header IPv4
49 | */
50 | struct pshdr_ip4 {
51 | uint32_t saddr;
52 | uint32_t daddr;
53 | uint8_t zero;
54 | uint8_t protocol;
55 | uint16_t len;
56 | };
57 |
58 | /**
59 | * vrrp_ip4_search_vip() - search one vip in vip list
60 | * if vip is found
61 | * set found = 1
62 | * _vip_ptr point to vip in vnet->vip_list
63 | */
64 | #define vrrp_ip4_search_vip(vnet, _vip_ptr, _addr, found) \
65 | do { \
66 | if (_addr != NULL) \
67 | list_for_each_entry_reverse(_vip_ptr, &vnet->vip_list, iplist) { \
68 | if ( _vip_ptr->ip_addr.s_addr == *_addr) {\
69 | found = 1; \
70 | break; \
71 | } \
72 | } \
73 | } while(0)
74 |
75 |
76 | /**
77 | * vrrp_ip4_mgroup() - join IPv4 VRRP multicast group
78 | */
79 | static int vrrp_ip4_mgroup(struct vrrp_net *vnet)
80 | {
81 | /* Join VRRP multicast group */
82 | struct ip_mreq group = { {0}, {0} };
83 | struct in_addr group_addr = { 0 };
84 |
85 | if (inet_pton(AF_INET, VRRP_MGROUP4, &group_addr) < 0) {
86 | log_error("vrid %d :: inet_pton - %m", vnet->vrid);
87 | return -1;
88 | }
89 | group.imr_multiaddr.s_addr = group_addr.s_addr;
90 | group.imr_interface.s_addr = vnet->vif.ip_addr.s_addr;
91 |
92 | if (setsockopt
93 | (vnet->socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, &group,
94 | sizeof(struct ip_mreq)) < 0) {
95 | log_error("vrid %d :: setsockopt - %m", vnet->vrid);
96 | return -1;
97 | }
98 |
99 | return 0;
100 | }
101 |
102 | /**
103 | * vrrp_ip4_cmp() - Compare VIP list between received vrrpkt and our instance
104 | * Return 0 if the list is the same,
105 | * the number of different VIP else
106 | */
107 | static int vrrp_ip4_viplist_cmp(struct vrrp_net *vnet, struct vrrphdr *vrrpkt)
108 | {
109 | /* compare IP address(es) */
110 | uint32_t *vip_addr =
111 | (uint32_t *) ((unsigned char *) vrrpkt + VRRP_PKTHDR_SIZE);
112 |
113 | uint32_t naddr = 0;
114 | int ndiff = 0;
115 |
116 | for (naddr = 0; naddr < vnet->naddr; ++naddr) {
117 | /* vip in vrrpkt */
118 | in_addr_t *addr = vip_addr + naddr;
119 |
120 | /* search in vrrp_ip list */
121 | struct vrrp_ip *vip_ptr = NULL;
122 | int found = 0;
123 | vrrp_ip4_search_vip(vnet, vip_ptr, addr, found);
124 |
125 | if (!found) {
126 | log_warning
127 | ("vrid %d :: Invalid pkt - Virtual IP address unexpected",
128 | vnet->vrid);
129 | ++ndiff;
130 | }
131 | }
132 | return ndiff;
133 | }
134 |
135 | /**
136 | * vrrp_ip4_recv() - Fill vrrp_l3 header from received pkt
137 | */
138 | static int vrrp_ip4_recv(int sock_fd, struct vrrp_recv *recv,
139 | unsigned char *buf, ssize_t buf_size, int *payload_pos)
140 | {
141 | ssize_t len;
142 | struct iphdr *ip;
143 |
144 | len = read(sock_fd, buf, buf_size);
145 | ip = (struct iphdr *) buf;
146 |
147 | recv->header.len = ip->ihl << 2;
148 | recv->header.proto = ip->protocol;
149 | recv->header.totlen = ntohs(ip->tot_len);
150 | recv->header.ttl = ip->ttl;
151 |
152 | /* saddr and daddr of the ip header */
153 | recv->ip_saddr.s_addr = ip->saddr;
154 | recv->ip_daddr.s_addr = ip->daddr;
155 |
156 | /* VRRP adv begin here */
157 | *payload_pos = recv->header.len;
158 |
159 | return len;
160 | }
161 |
162 | /**
163 | * vrrp_ip4_getsize() - return the current size of vrrp instance
164 | */
165 | static int vrrp_ip4_getsize(const struct vrrp_net *vnet)
166 | {
167 | return sizeof(struct vrrphdr) + vnet->naddr * sizeof(uint32_t) +
168 | VRRP_AUTH_SIZE;
169 | }
170 |
171 | /**
172 | * vrrp_ip4_chksum() - compute vrrp adv chksum
173 | */
174 | static uint16_t vrrp_ip4_chksum(const struct vrrp_net *vnet,
175 | struct vrrphdr *pkt,
176 | union vrrp_ipx_addr *ipx_saddr,
177 | union vrrp_ipx_addr *ipx_daddr)
178 | {
179 | /* reset chksum */
180 | pkt->chksum = 0;
181 |
182 | if ((pkt->version_type >> 4) == RFC3768)
183 | return cksum((unsigned short *) pkt, vrrp_ip4_getsize(vnet));
184 |
185 | if ((pkt->version_type >> 4) == RFC5798) {
186 | const struct iovec *iov_iph = &vnet->__adv[1];
187 | const struct iphdr *iph = iov_iph->iov_base;
188 |
189 | /* get saddr and daddr */
190 | uint32_t saddr = 0;
191 | uint32_t daddr = 0;
192 |
193 | if (ipx_saddr != NULL)
194 | saddr = ipx_saddr->addr.s_addr;
195 | if (ipx_daddr != NULL)
196 | daddr = ipx_daddr->addr.s_addr;
197 |
198 | /* pseudo_header ipv4 */
199 | struct pshdr_ip4 psh = { 0 };
200 |
201 | /* if saddr and daddr are not specified, use addresses from iphdr */
202 | psh.saddr = (saddr ? saddr : iph->saddr);
203 | psh.daddr = (daddr ? daddr : iph->daddr);
204 | psh.zero = 0;
205 | psh.protocol = iph->protocol;
206 | psh.len = htons(vrrp_ip4_getsize(vnet));
207 |
208 | uint32_t psh_size =
209 | sizeof(struct pshdr_ip4) + vrrp_ip4_getsize(vnet);
210 |
211 | unsigned short buf[psh_size / sizeof(short)];
212 |
213 | memcpy(buf, &psh, sizeof(struct pshdr_ip4));
214 | memcpy(buf + sizeof(struct pshdr_ip4) / sizeof(short), pkt,
215 | vrrp_ip4_getsize(vnet));
216 |
217 | return cksum(buf, psh_size);
218 | }
219 |
220 | return 0;
221 | }
222 |
223 | /**
224 | * vrrp_ip4_ntop() - network to string representation
225 | */
226 | static const char *vrrp_ip4_ntop(union vrrp_ipx_addr *ipx, char *dst)
227 | {
228 | return inet_ntop(AF_INET, &ipx->addr, dst, INET_ADDRSTRLEN);
229 | }
230 |
231 | /**
232 | * vrrp_ip4_pton() - string representation to network
233 | */
234 | static int vrrp_ip4_pton(union vrrp_ipx_addr *dst, const char *src)
235 | {
236 | return inet_pton(AF_INET, src, &dst->addr);
237 | }
238 |
239 |
240 | /**
241 | * vrrp_ip4_cmp() - compare two vipx
242 | */
243 | int vrrp_ip4_cmp(union vrrp_ipx_addr *s1, union vrrp_ipx_addr *s2)
244 | {
245 | return ntohl(s1->addr.s_addr) - ntohl(s2->addr.s_addr);
246 | }
247 |
248 | /**
249 | * vrrp_ip4_setsockopt() - no need to setsockopt() in IPv4
250 | */
251 | static int vrrp_ip4_setsockopt( __attribute__ ((unused))
252 | int sock_fd, __attribute__ ((unused))
253 | int vrid)
254 | {
255 | /* nop */
256 | return 0;
257 | }
258 |
259 | /* exported VRRP_IP4 helper */
260 | struct vrrp_ipx VRRP_IP4 = {
261 | .family = AF_INET,
262 | .setsockopt = vrrp_ip4_setsockopt,
263 | .mgroup = vrrp_ip4_mgroup,
264 | .recv = vrrp_ip4_recv,
265 | .cmp = vrrp_ip4_cmp,
266 | .chksum = vrrp_ip4_chksum,
267 | .viplist_cmp = vrrp_ip4_viplist_cmp,
268 | .getsize = vrrp_ip4_getsize,
269 | .ipx_pton = vrrp_ip4_pton,
270 | .ipx_ntop = vrrp_ip4_ntop,
271 | };
272 |
--------------------------------------------------------------------------------
/vrrp_ip6.c:
--------------------------------------------------------------------------------
1 | /*
2 | * vrrp_ip6.c - IPv6 helpers functions
3 | *
4 | * Copyright (C) 2014 Arnaud Andre
5 | *
6 | * This file is part of uvrrpd.
7 | *
8 | * uvrrpd is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU General Public License as published by
10 | * the Free Software Foundation, either version 3 of the License, or
11 | * (at your option) any later version.
12 | *
13 | * uvrrpd is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU General Public License
19 | * along with uvrrpd. If not, see .
20 | */
21 |
22 | #ifdef HAVE_IP6
23 |
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 | /* ifreq + ioctl */
34 | #include
35 | #include
36 | #include
37 | #include
38 | #include /* NI_MAXHOST */
39 |
40 | #include "vrrp_ipx.h"
41 | #include "vrrp_net.h"
42 | #include "log.h"
43 | #include "common.h"
44 |
45 | #define VRRP_MGROUP6 "ff02::12"
46 | #define IP6HDR_SIZE sizeof(struct ip6_hdr)
47 |
48 | /**
49 | * pshdr_ip6 - pseudo header IPv6
50 | */
51 | struct pshdr_ip6 {
52 | struct in6_addr saddr;
53 | struct in6_addr daddr;
54 | uint32_t len;
55 | uint8_t zeros[3];
56 | uint8_t next_header;
57 | };
58 |
59 | /**
60 | * vrrp_ip6_search_vip() - search one vip in vip list
61 | * if vip is found
62 | * set found = 1
63 | * _vip_ptr point to vip in vnet->vip_list
64 | */
65 | #define vrrp_ip6_search_vip(vnet, _vip_ptr, _addr, found) \
66 | do { \
67 | list_for_each_entry_reverse(_vip_ptr, &vnet->vip_list, iplist) { \
68 | if (memcmp(&(_vip_ptr->ip_addr6), _addr, sizeof(struct in6_addr)) == 0) { \
69 | found = 1; \
70 | break; \
71 | }\
72 | } \
73 | } while(0)
74 |
75 | /**
76 | * vrrp_ip6_setsockopt() - Set socket option
77 | * used to find ancillary data in recvmsg()
78 | * see vrrp_ip6_recv()
79 | */
80 | static int vrrp_ip6_setsockopt(int socket, int vrid)
81 | {
82 | int on = 1;
83 |
84 | /* IPV6_RECVPKTINFO */
85 | if (setsockopt
86 | (socket, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)) < 0) {
87 | log_error("vrid %d :: setsockopt - %m", vrid);
88 | return -1;
89 | }
90 |
91 | /* IPV6_RECVHOPLIMIT */
92 | if (setsockopt
93 | (socket, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, sizeof(on)) < 0) {
94 | log_error("vrid %d :: setsockopt - %m", vrid);
95 | return -1;
96 | }
97 |
98 | return 0;
99 | }
100 |
101 | /**
102 | * vrrp_net_join_mgroup6() - join IPv6 VRRP multicast group
103 | */
104 | static int vrrp_ip6_mgroup(struct vrrp_net *vnet)
105 | {
106 | /* Join VRRP multicast group */
107 | struct ipv6_mreq group = { IN6ADDR_ANY_INIT, 0 };
108 | struct in6_addr group_addr = IN6ADDR_ANY_INIT;
109 |
110 | if (inet_pton(AF_INET6, VRRP_MGROUP6, &group_addr) < 0) {
111 | log_error("vrid %d :: inet_pton - %m", vnet->vrid);
112 | return -1;
113 | }
114 |
115 | memcpy(&group.ipv6mr_multiaddr, &group_addr, sizeof(struct in6_addr));
116 |
117 | group.ipv6mr_interface = if_nametoindex(vnet->vif.ifname);
118 |
119 | if (setsockopt
120 | (vnet->socket, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &group,
121 | sizeof(struct ipv6_mreq)) < 0) {
122 | log_error("vrid %d :: setsockopt - %m", vnet->vrid);
123 | return -1;
124 | }
125 |
126 | return 0;
127 | }
128 |
129 | /**
130 | * vrrp_ip6_cmp() - Compare VIP list between received vrrpkt and our instance
131 | * Return 0 if the list is the same,
132 | * the number of differente VIP else
133 | */
134 | static int vrrp_ip6_viplist_cmp(struct vrrp_net *vnet, struct vrrphdr *vrrpkt)
135 | {
136 | uint32_t *vip_addr =
137 | (uint32_t *) ((unsigned char *) vrrpkt + VRRP_PKTHDR_SIZE);
138 |
139 | uint32_t pos = 0;
140 | int naddr = 0;
141 | int ndiff = 0;
142 |
143 | while (naddr < vnet->naddr) {
144 | /* vip in vrrpkt */
145 | struct in6_addr *vip = (struct in6_addr *) (vip_addr + pos);
146 |
147 | /* search in vrrp_ip list */
148 | struct vrrp_ip *vip_ptr = NULL;
149 | int found = 0;
150 |
151 | vrrp_ip6_search_vip(vnet, vip_ptr, vip->s6_addr, found);
152 |
153 | if (!found) {
154 | char host[NI_MAXHOST];
155 | log_warning
156 | ("vrid %d :: Invalid pkt - Virtual IPv6 address unexpected %s",
157 | vnet->vrid, inet_ntop(vnet->family, vip, host,
158 | sizeof(host)));
159 | ++ndiff;
160 | }
161 | pos += 4;
162 | ++naddr;
163 | }
164 | return ndiff;
165 | }
166 |
167 | /**
168 | * find_ancillary() - search & find IPv6 ancillary data after
169 | * receiving data in a struct msghdr msg (recvmsg())
170 | */
171 | static inline void *find_ancillary(struct msghdr *msg, int cmsg_type)
172 | {
173 | struct cmsghdr *cmsg = NULL;
174 |
175 | for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL;
176 | cmsg = CMSG_NXTHDR(msg, cmsg)) {
177 | if ((cmsg->cmsg_level == IPPROTO_IPV6)
178 | && (cmsg->cmsg_type == cmsg_type)) {
179 | return (CMSG_DATA(cmsg));
180 | }
181 | }
182 |
183 | return NULL;
184 | }
185 |
186 | /**
187 | * vrrp_ip6_recv() - Fill vrrp_ipx_header from received pkt
188 | */
189 | static int vrrp_ip6_recv(int sock_fd, struct vrrp_recv *recv,
190 | unsigned char *buf, ssize_t buf_size, int *payload_pos)
191 | {
192 | ssize_t len;
193 |
194 | /* IPv6 raw sockets return no IP header. We must query
195 | * src/dest via socket options/ancillary data */
196 | struct msghdr msg;
197 | struct sockaddr_in6 src;
198 | struct iovec iov;
199 | uint8_t ancillary[64];
200 |
201 | msg.msg_name = &src;
202 | msg.msg_namelen = sizeof(src);
203 | iov.iov_base = buf;
204 | iov.iov_len = buf_size;
205 | msg.msg_iov = &iov;
206 | msg.msg_iovlen = 1;
207 | msg.msg_control = ancillary;
208 | msg.msg_controllen = sizeof(ancillary);
209 | msg.msg_flags = 0;
210 |
211 | len = recvmsg(sock_fd, &msg, 0);
212 |
213 | if (len < 0) {
214 | log_error("recvmsg - %m");
215 | return -1;
216 | }
217 |
218 | /* src address */
219 | memcpy(&recv->ip_saddr6, &src.sin6_addr, sizeof(struct in6_addr));
220 |
221 | /* hoplimit */
222 | uint8_t *opt = find_ancillary(&msg, IPV6_HOPLIMIT);
223 | if (opt == NULL) {
224 | log_error("recvmsg - unknown hop limit");
225 | return -1;
226 | }
227 |
228 | recv->header.ttl = *(int *) opt;
229 |
230 | /* dst address */
231 | opt = find_ancillary(&msg, IPV6_PKTINFO);
232 | if (opt == NULL) {
233 | log_error("recvmsg - unknown dst address");
234 | return -1;
235 | }
236 |
237 | struct in6_pktinfo *pktinfo = (struct in6_pktinfo *) opt;
238 |
239 | memcpy(&recv->ip_daddr6, &pktinfo->ipi6_addr, sizeof(struct in6_addr));
240 |
241 | /* other options */
242 | recv->header.len = sizeof(struct ip6_hdr);
243 | recv->header.totlen = recv->header.len + len;
244 | /* kludge, we force it since we have no way to read it in recvmsg().
245 | * But we have set IPPROTO_VRRP in vrrp_net_socket() */
246 | recv->header.proto = IPPROTO_VRRP;
247 |
248 | /* buf is directly filled with VRRP adv
249 | * no need to skip IPv6 header */
250 | *payload_pos = 0;
251 |
252 | return len;
253 | }
254 |
255 | /**
256 | * vrrp_ip6_getsize() - return the current size of vrrp instance
257 | */
258 | static int vrrp_ip6_getsize(const struct vrrp_net *vnet)
259 | {
260 | return sizeof(struct vrrphdr) + vnet->naddr * sizeof(struct in6_addr);
261 | }
262 |
263 | /**
264 | * vrrp_ip6_chksum() - compute VRRP adv chksum
265 | */
266 | uint16_t vrrp_ip6_chksum(const struct vrrp_net *vnet, struct vrrphdr *pkt,
267 | union vrrp_ipx_addr *ipx_saddr,
268 | union vrrp_ipx_addr *ipx_daddr)
269 | {
270 | /* reset chksum */
271 | pkt->chksum = 0;
272 |
273 | const struct iovec *iov_iph = &vnet->__adv[1];
274 | const struct ip6_hdr *iph = iov_iph->iov_base;
275 |
276 | /* pseudo_header ipv6 */
277 | struct pshdr_ip6 psh = { IN6ADDR_ANY_INIT,
278 | IN6ADDR_ANY_INIT,
279 | 0,
280 | {0, 0, 0},
281 | 0
282 | };
283 |
284 | if ((ipx_saddr != NULL) && (ipx_daddr != NULL)) {
285 | memcpy(&psh.saddr, &ipx_saddr->addr6, sizeof(struct in6_addr));
286 | memcpy(&psh.daddr, &ipx_daddr->addr6, sizeof(struct in6_addr));
287 | }
288 | else {
289 | memcpy(&psh.saddr, &iph->ip6_src, sizeof(struct in6_addr));
290 | memcpy(&psh.daddr, &iph->ip6_dst, sizeof(struct in6_addr));
291 | }
292 |
293 |
294 | bzero(&psh.zeros, sizeof(psh.zeros));
295 | psh.next_header = IPPROTO_VRRP;
296 | psh.len = htons(vrrp_ip6_getsize(vnet));
297 |
298 | uint32_t psh_size = sizeof(struct pshdr_ip6) + vrrp_ip6_getsize(vnet);
299 | unsigned short buf[psh_size / sizeof(short)];
300 |
301 | memcpy(buf, &psh, sizeof(struct pshdr_ip6));
302 | memcpy(buf + sizeof(struct pshdr_ip6) / sizeof(short), pkt,
303 | vrrp_ip6_getsize(vnet));
304 |
305 | return cksum(buf, psh_size);
306 | }
307 |
308 | /**
309 | * vrrp_ip6_ntop() - network to string representation
310 | */
311 | static const char *vrrp_ip6_ntop(union vrrp_ipx_addr *ipx, char *dst)
312 | {
313 | return inet_ntop(AF_INET6, &ipx->addr6, dst, INET6_ADDRSTRLEN);
314 | }
315 |
316 | /**
317 | * vrrp_ip6_pton() - string representation to network
318 | */
319 | static int vrrp_ip6_pton(union vrrp_ipx_addr *dst, const char *src)
320 | {
321 | return inet_pton(AF_INET6, src, &dst->addr6);
322 | }
323 |
324 | /**
325 | * vrrp_ip6_cmp() - compare two vipx
326 | */
327 | int vrrp_ip6_cmp(union vrrp_ipx_addr *s1, union vrrp_ipx_addr *s2)
328 | {
329 | return memcmp(&s1->addr6, &s2->addr6, sizeof(struct in6_addr));
330 | }
331 |
332 | /* exported VRRP_IP6 helper */
333 | struct vrrp_ipx VRRP_IP6 = {
334 | .family = AF_INET6,
335 | .setsockopt = vrrp_ip6_setsockopt,
336 | .mgroup = vrrp_ip6_mgroup,
337 | .recv = vrrp_ip6_recv,
338 | .cmp = vrrp_ip6_cmp,
339 | .chksum = vrrp_ip6_chksum,
340 | .getsize = vrrp_ip6_getsize,
341 | .viplist_cmp = vrrp_ip6_viplist_cmp,
342 | .ipx_pton = vrrp_ip6_pton,
343 | .ipx_ntop = vrrp_ip6_ntop
344 | };
345 |
346 | #endif /* HAVE_IP6 */
347 |
--------------------------------------------------------------------------------
/vrrp_ipx.h:
--------------------------------------------------------------------------------
1 | /**
2 | * vrrp_ipx.h
3 | *
4 | * Copyright (C) 2014 Arnaud Andre
5 | *
6 | * This file is part of uvrrpd.
7 | *
8 | * uvrrpd is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU General Public License as published by
10 | * the Free Software Foundation, either version 3 of the License, or
11 | * (at your option) any later version.
12 | *
13 | * uvrrpd is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU General Public License
19 | * along with uvrrpd. If not, see .
20 | */
21 |
22 | #ifndef _VRRP_IPX_
23 | #define _VRRP_IPX_
24 |
25 |
26 | /* from vrrp_net.h */
27 | struct vrrp_net;
28 | struct vrrphdr;
29 | struct vrrp_recv;
30 |
31 | /**
32 | * struct vrrp_ipx_header - IPvX header informations from received adv pkt
33 | */
34 | struct vrrp_ipx_header {
35 | int len;
36 | int proto;
37 | int totlen;
38 | int ttl;
39 | };
40 |
41 | /**
42 | * union vrrp_ipx_addr - IPv4 and IPv6 addr struct
43 | */
44 | union vrrp_ipx_addr {
45 | struct in_addr addr;
46 | #ifdef HAVE_IP6
47 | struct in6_addr addr6;
48 | #endif
49 | };
50 |
51 | /**
52 | * struct vrrp_ipx - Helper functions
53 | */
54 | struct vrrp_ipx {
55 | /* AF_INET or AF6_INET */
56 | int family;
57 |
58 | /* setsockopt() - socket options */
59 | int (*setsockopt) (int, int);
60 |
61 | /* mgroup() - join IPvX VRRP multicast group */
62 | int (*mgroup) (struct vrrp_net *);
63 |
64 | /* cmp() - Compare two IPvX address */
65 | int (*cmp) (union vrrp_ipx_addr *, union vrrp_ipx_addr *);
66 |
67 | /* recv() - Read received pkt and fetch/store information
68 | * in struct vrrp_recv */
69 | int (*recv) (int, struct vrrp_recv *, unsigned char *, ssize_t, int *);
70 |
71 | /* getsize() - get size of IPvX VRRP advertisement pkt */
72 | int (*getsize) (const struct vrrp_net *);
73 |
74 | /* viplist_cmp() - compare VRRP Virtual IPvX list */
75 | int (*viplist_cmp) (struct vrrp_net *, struct vrrphdr *);
76 |
77 | /* chksum() - compute IPvX checksum while building
78 | * advertisement packet */
79 | uint16_t(*chksum) (const struct vrrp_net *, struct vrrphdr *,
80 | union vrrp_ipx_addr *, union vrrp_ipx_addr *);
81 |
82 | /* ipx_ntop() - call ntop() on IPvX addr */
83 | const char *(*ipx_ntop) (union vrrp_ipx_addr *, char *);
84 |
85 | /* ipx_pton() - call pton() on IPvX addr */
86 | int (*ipx_pton) (union vrrp_ipx_addr *, const char *);
87 | };
88 |
89 | /* IP4 and IP6 internal modules */
90 | extern struct vrrp_ipx VRRP_IP4; /* IPv4 module */
91 | #ifdef HAVE_IP6
92 | extern struct vrrp_ipx VRRP_IP6; /* IPv6 module */
93 | #endif
94 |
95 | /**
96 | * vrrp_ipx_set() - Set l3 helper for vrrp_net
97 | */
98 | static inline struct vrrp_ipx *vrrp_ipx_set(int family)
99 | {
100 | if (family == AF_INET) {
101 | return &VRRP_IP4;
102 | }
103 | #ifdef HAVE_IP6
104 | if (family == AF_INET6) {
105 | return &VRRP_IP6;
106 | }
107 | #endif
108 | return NULL;
109 | }
110 |
111 | #endif /* _VRRP_IPX_ */
112 |
--------------------------------------------------------------------------------
/vrrp_na.c:
--------------------------------------------------------------------------------
1 | /*
2 | * vrrp_na.c - Neighbour Advertisement
3 | *
4 | * TODO : need work to use chksum helper in vrrp_ip6.c
5 | *
6 | * Copyright (C) 2014 Arnaud Andre
7 | *
8 | * This file is part of uvrrpd.
9 | *
10 | * uvrrpd is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU General Public License as published by
12 | * the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * uvrrpd is distributed in the hope that it will be useful,
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 | * GNU General Public License for more details.
19 | *
20 | * You should have received a copy of the GNU General Public License
21 | * along with uvrrpd. If not, see .
22 | */
23 |
24 | #ifdef HAVE_IP6
25 |
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include // struct nd_neighbor_advert
33 |
34 | #include "log.h"
35 | #include "vrrp.h"
36 | #include "vrrp_net.h"
37 |
38 | #define IN6ADDR_MCAST "ff02::1"
39 |
40 | #define ETHDR_SIZE sizeof(struct ether_header)
41 |
42 | /**
43 | * ether_header vrrp_na_eth
44 | */
45 | static struct ether_header vrrp_na_eth = {
46 | .ether_dhost = {0x33, 0x33, 0x00,
47 | 0x00, 0x00, 0x01},
48 | .ether_shost = {0x00,
49 | 0x00,
50 | 0x52,
51 | 0x00,
52 | 0x01,
53 | 0x00}, /* vrrp->vrid */
54 | };
55 |
56 | /**
57 | * pshdr_ip6 - pseudo header IPv6
58 | */
59 | struct pshdr_ip6 {
60 | struct in6_addr saddr;
61 | struct in6_addr daddr;
62 | uint32_t len;
63 | uint8_t zeros[3];
64 | uint8_t next_header;
65 | };
66 |
67 | /**
68 | * vrrp_na_eth_build()
69 | */
70 | static int vrrp_na_eth_build(struct iovec *iov, const uint8_t vrid)
71 | {
72 | iov->iov_base = malloc(sizeof(struct ether_header));
73 |
74 | struct ether_header *hdr = iov->iov_base;
75 |
76 | if (hdr == NULL) {
77 | log_error("vrid %d :: malloc - %m", vrid);
78 | return -1;
79 | }
80 |
81 | memcpy(hdr, &vrrp_na_eth, sizeof(struct ether_header));
82 |
83 | hdr->ether_shost[5] = vrid;
84 | hdr->ether_type = htons(ETH_P_IPV6);
85 |
86 | iov->iov_len = ETHDR_SIZE;
87 |
88 | return 0;
89 | }
90 |
91 | /**
92 | * vrrp_na_ip6_build()
93 | */
94 | static int vrrp_na_ip6_build(struct iovec *iov, struct vrrp_ip *ip,
95 | const struct vrrp_net *vnet)
96 | {
97 | iov->iov_base = malloc(sizeof(struct ip6_hdr));
98 |
99 | struct ip6_hdr *ip6h = iov->iov_base;
100 |
101 | if (ip6h == NULL) {
102 | log_error("vrid %d :: malloc - %m", vnet->vrid);
103 | return -1;
104 | }
105 |
106 | ip6h->ip6_flow = htonl((6 << 28) | (0 << 20) | 0);
107 | ip6h->ip6_plen = htons(sizeof(struct nd_neighbor_advert));
108 | ip6h->ip6_nxt = IPPROTO_ICMPV6;
109 | ip6h->ip6_hlim = 0xff;
110 |
111 | memcpy(&ip6h->ip6_src, &ip->ip_addr6, sizeof(struct in6_addr));
112 |
113 | if (inet_pton(AF_INET6, IN6ADDR_MCAST, &(ip6h->ip6_dst)) != 1) {
114 | log_error("vrid %d :: inet_pton - %m", vnet->vrid);
115 | return -1;
116 | }
117 |
118 | iov->iov_len = sizeof(struct ip6_hdr);
119 |
120 | return 0;
121 | }
122 |
123 |
124 | /**
125 | * vrrp_na_chksum() - compute na chksum
126 | */
127 | uint16_t vrrp_na_chksum(struct iovec * iov, struct nd_neighbor_advert * na)
128 | {
129 | /* reset chksum */
130 | na->nd_na_hdr.icmp6_cksum = 0;
131 |
132 | const struct ip6_hdr *iph = iov->iov_base;
133 |
134 | /* pseudo_header ipv6 */
135 | struct pshdr_ip6 psh = { IN6ADDR_ANY_INIT, /* saddr */
136 | IN6ADDR_ANY_INIT, /* daddr */
137 | 0, /* length */
138 | {0, 0, 0}, /* zeros[3] */
139 | 0 /* next_header */
140 | };
141 |
142 | memcpy(&psh.saddr, &iph->ip6_src, sizeof(struct in6_addr));
143 | memcpy(&psh.daddr, &iph->ip6_dst, sizeof(struct in6_addr));
144 |
145 | bzero(&psh.zeros, sizeof(psh.zeros));
146 | psh.next_header = IPPROTO_ICMPV6;
147 | psh.len = htons(sizeof(struct nd_neighbor_advert));
148 |
149 | uint32_t psh_size =
150 | sizeof(struct pshdr_ip6) + sizeof(struct nd_neighbor_advert);
151 | unsigned short buf[psh_size / sizeof(short)];
152 |
153 | memcpy(buf, &psh, sizeof(struct pshdr_ip6));
154 | memcpy(buf + sizeof(struct pshdr_ip6) / sizeof(short), na,
155 | sizeof(struct nd_neighbor_advert));
156 |
157 | return cksum(buf, psh_size);
158 | }
159 |
160 | /**
161 | * vrrp_na_build()
162 | */
163 | static int vrrp_na_build(struct iovec *iov, struct vrrp_ip *ip,
164 | const struct vrrp_net *vnet)
165 | {
166 | iov->iov_base = malloc(sizeof(struct nd_neighbor_advert));
167 |
168 | struct nd_neighbor_advert *na = iov->iov_base;
169 |
170 | if (na == NULL) {
171 | log_error("vrid %d :: malloc - %m", vnet->vrid);
172 | return -1;
173 | }
174 |
175 | na->nd_na_hdr.icmp6_type = ND_NEIGHBOR_ADVERT;
176 | na->nd_na_hdr.icmp6_code = 0;
177 | na->nd_na_hdr.icmp6_cksum = 0;
178 | /* Set R/S/O flags as = R=1, S=0, O=1 (RFC 5798, 6.4.2.(395)) */
179 | na->nd_na_flags_reserved = ND_NA_FLAG_ROUTER | ND_NA_FLAG_OVERRIDE;
180 | memcpy(&na->nd_na_target, &ip->ip_addr6, sizeof(struct in6_addr));
181 |
182 | na->nd_na_hdr.icmp6_cksum = vrrp_na_chksum(&ip->__topology[1], na);
183 |
184 | iov->iov_len = sizeof(struct nd_neighbor_advert);
185 |
186 | return 0;
187 | }
188 |
189 | /**
190 | * vrrp_na_send() - for each vip send an unsollicited neighbor advertisement
191 | */
192 | int vrrp_na_send(struct vrrp_net *vnet)
193 | {
194 | struct vrrp_ip *vip_ptr = NULL;
195 |
196 | /* we have to send one na by vip */
197 | list_for_each_entry_reverse(vip_ptr, &vnet->vip_list, iplist) {
198 | vrrp_net_send(vnet, vip_ptr->__topology,
199 | ARRAY_SIZE(vip_ptr->__topology));
200 | }
201 |
202 | return 0;
203 | }
204 |
205 | /**
206 | * vrrp_na_init()
207 | */
208 | int vrrp_na_init(struct vrrp_net *vnet)
209 | {
210 | int status = -1;
211 |
212 | /* we have to build one na pkt by vip */
213 | struct vrrp_ip *vip_ptr = NULL;
214 |
215 | list_for_each_entry_reverse(vip_ptr, &vnet->vip_list, iplist) {
216 | status = vrrp_na_eth_build(&vip_ptr->__topology[0], vnet->vrid);
217 | status |=
218 | vrrp_na_ip6_build(&vip_ptr->__topology[1], vip_ptr, vnet);
219 | status |= vrrp_na_build(&vip_ptr->__topology[2], vip_ptr, vnet);
220 | }
221 |
222 | return status;
223 | }
224 |
225 |
226 | /**
227 | * vrrp_na_cleanup()
228 | */
229 | void vrrp_na_cleanup(struct vrrp_net *vnet)
230 | {
231 | /* clean na buffer for each vrrp_ip addr */
232 | struct vrrp_ip *vip_ptr = NULL;
233 |
234 | list_for_each_entry(vip_ptr, &vnet->vip_list, iplist) {
235 |
236 | /* clean iovec */
237 | for (int i = 0; i < 3; ++i) {
238 | struct iovec *iov = &vip_ptr->__topology[i];
239 | free(iov->iov_base);
240 | }
241 |
242 | }
243 | }
244 |
245 | #endif /* HAVE_IP6 */
246 |
--------------------------------------------------------------------------------
/vrrp_na.h:
--------------------------------------------------------------------------------
1 | /*
2 | * vrrp_na.h - Neighbour Advertisement
3 | *
4 | * Copyright (C) 2014 Arnaud Andre
5 | *
6 | * This file is part of uvrrpd.
7 | *
8 | * uvrrpd is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU General Public License as published by
10 | * the Free Software Foundation, either version 3 of the License, or
11 | * (at your option) any later version.
12 | *
13 | * uvrrpd is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU General Public License
19 | * along with uvrrpd. If not, see .
20 | */
21 |
22 | #ifdef HAVE_IP6
23 |
24 | #ifndef _VRRP_NA_H_
25 | #define _VRRP_NA_H_
26 |
27 | int vrrp_na_init(struct vrrp_net *vnet);
28 | void vrrp_na_cleanup(struct vrrp_net *vnet);
29 | int vrrp_na_send(struct vrrp_net *vnet);
30 |
31 | #endif /* _VRRP_NA_H_ */
32 |
33 | #endif /* HAVE_IP6 */
34 |
--------------------------------------------------------------------------------
/vrrp_net.c:
--------------------------------------------------------------------------------
1 | /*
2 | * vrrp_net.c - net layer
3 | *
4 | * Copyright (C) 2014 Arnaud Andre
5 | *
6 | * This file is part of uvrrpd.
7 | *
8 | * uvrrpd is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU General Public License as published by
10 | * the Free Software Foundation, either version 3 of the License, or
11 | * (at your option) any later version.
12 | *
13 | * uvrrpd is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU General Public License
19 | * along with uvrrpd. If not, see .
20 | */
21 |
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 | /* ifreq + ioctl */
33 | #include
34 | #include
35 |
36 | #include
37 | #include
38 | #include /* NI_MAXHOST */
39 |
40 | #include "vrrp.h"
41 | #include "vrrp_net.h"
42 | #include "vrrp_adv.h"
43 |
44 | #include "common.h"
45 | #include "list.h"
46 | #include "log.h"
47 |
48 | #include "linux/types.h"
49 |
50 | #define VRRP_TTL 255
51 |
52 | static inline void vrrp_net_invalidate_buffer(struct vrrp_net *vnet);
53 |
54 | /**
55 | * vrrp_net_init() - init struct vrrp_net of vrrp instance
56 | */
57 | void vrrp_net_init(struct vrrp_net *vnet)
58 | {
59 | vnet->vrid = 0;
60 | vnet->naddr = 0;
61 | vnet->socket = 0;
62 | vnet->xmit = 0;
63 | vnet->family = AF_INET;
64 | vnet->ipx_helper = NULL;
65 |
66 | /* init VRRP IPs list */
67 | INIT_LIST_HEAD(&vnet->vip_list);
68 |
69 | /* init vrrp interface */
70 | bzero((void *) &vnet->vif, sizeof(struct vrrp_if));
71 |
72 | /* init pkt buffer */
73 | bzero((void *) &vnet->__pkt, sizeof(struct vrrp_recv));
74 | }
75 |
76 | /**
77 | * vrrp_net_cleanup() - cleanup struct vrrp_net
78 | */
79 | void vrrp_net_cleanup(struct vrrp_net *vnet)
80 | {
81 | /* clean VIP addr */
82 | struct vrrp_ip *vip_ptr = NULL;
83 | struct vrrp_ip *n = NULL;
84 | list_for_each_entry_safe(vip_ptr, n, &vnet->vip_list, iplist)
85 | free(vip_ptr);
86 |
87 | free(vnet->vif.ifname);
88 |
89 | /* close sockets */
90 | close(vnet->socket);
91 | close(vnet->xmit);
92 | }
93 |
94 | /**
95 | * vrrp_net_socket() - create VRRP socket destined to receive VRRP pkt
96 | */
97 | int vrrp_net_socket(struct vrrp_net *vnet)
98 | {
99 | /* Open RAW socket */
100 | vnet->socket = socket(vnet->family, SOCK_RAW, IPPROTO_VRRP);
101 |
102 | if (vnet->socket < 0) {
103 | log_error("vrid %d :: socket - %m", vnet->vrid);
104 | return -1;
105 | }
106 |
107 | vnet->ipx_helper = vrrp_ipx_set(vnet->family);
108 |
109 | if (vnet->ipx_helper == NULL) {
110 | log_error("family not valid");
111 | return -1;
112 | }
113 |
114 | int status = -1;
115 |
116 | status = vnet->set_sockopt(vnet->socket, vnet->vrid);
117 | status |= vnet->join_mgroup(vnet);
118 |
119 | return status;
120 | }
121 |
122 | /**
123 | * vrrp_net_socket_xmit() - open raw VRRP xmit socket
124 | */
125 | int vrrp_net_socket_xmit(struct vrrp_net *vnet)
126 | {
127 | vnet->xmit = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
128 |
129 | if (vnet->xmit < 0) {
130 | log_error("vrid %d :: socket xmit - %m", vnet->vrid);
131 | return -1;
132 | }
133 |
134 | return 0;
135 | }
136 |
137 |
138 | /**
139 | * vrrp_net_vif_getaddr() - get IPvX addr from a VRRP interface
140 | */
141 | int vrrp_net_vif_getaddr(struct vrrp_net *vnet)
142 | {
143 |
144 | struct ifaddrs *ifaddr, *ifa;
145 | int family;
146 |
147 | if (getifaddrs(&ifaddr) == -1) {
148 | log_error("vrid %d :: getifaddrs - %m", vnet->vrid);
149 | return -1;
150 | }
151 |
152 | /* search address */
153 | for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
154 | if (strcmp(ifa->ifa_name, vnet->vif.ifname) != 0)
155 | continue;
156 |
157 | if (ifa->ifa_addr == NULL)
158 | continue;
159 |
160 | family = ifa->ifa_addr->sa_family;
161 |
162 | if (family != vnet->family)
163 | continue;
164 |
165 | if (vnet->family == AF_INET) {
166 | vnet->vif.ip_addr.s_addr =
167 | ((struct sockaddr_in *) ifa->ifa_addr)->
168 | sin_addr.s_addr;
169 | }
170 | #ifdef HAVE_IP6
171 | else { /* AF_INET6 */
172 | struct sockaddr_in6 *src =
173 | (struct sockaddr_in6 *) ifa->ifa_addr;
174 | memcpy(&vnet->vif.ip_addr6, &src->sin6_addr,
175 | sizeof(struct in6_addr));
176 | }
177 | #endif /* HAVE_IP6 */
178 | }
179 |
180 | freeifaddrs(ifaddr);
181 |
182 | vrrp_net_vif_mtu(vnet);
183 |
184 | return 0;
185 | }
186 |
187 | /**
188 | * vrrp_net_vif_mtu() - get MTU of vrrp interface
189 | */
190 | int vrrp_net_vif_mtu(struct vrrp_net *vnet)
191 | {
192 | struct ifreq ifr;
193 |
194 | strncpy(ifr.ifr_name, vnet->vif.ifname, IFNAMSIZ - 1);
195 |
196 | int fd = socket(AF_INET, SOCK_DGRAM, 0);
197 |
198 | ifr.ifr_addr.sa_family = AF_INET;
199 |
200 | if (ioctl(fd, SIOCGIFMTU, &ifr) < 0) {
201 | log_error("vrid %d :: ioctl - %m", vnet->vrid);
202 | return -1;
203 | }
204 |
205 | vnet->vif.mtu = ifr.ifr_mtu;
206 | log_debug("%s mtu : %d", vnet->vif.ifname, vnet->vif.mtu);
207 |
208 | close(fd);
209 |
210 | return 0;
211 | }
212 |
213 |
214 | /**
215 | * vrrp_net_vip_set() - register VRRP virtual IPvX addresses
216 | */
217 | int vrrp_net_vip_set(struct vrrp_net *vnet, const char *ip)
218 | {
219 | struct vrrp_ip *vip = malloc(sizeof(struct vrrp_ip));
220 |
221 | if (vip == NULL) {
222 | log_error("vrid %d :: malloc - %m", vnet->vrid);
223 | return -1;
224 | }
225 |
226 | /* split ip / netmask */
227 | int status = -1;
228 |
229 | if (vnet->family == AF_INET)
230 | status =
231 | split_ip_netmask(vnet->family, ip, &vip->ip_addr,
232 | &vip->netmask);
233 |
234 | #ifdef HAVE_IP6
235 | if (vnet->family == AF_INET6)
236 | status =
237 | split_ip_netmask(vnet->family, ip, &vip->ip_addr6,
238 | &vip->netmask);
239 | #endif /* HAVE_IP6 */
240 |
241 | if (status != 0) {
242 | fprintf(stderr, "vrid %d :: invalid IP addr %s", vnet->vrid,
243 | ip);
244 | free(vip);
245 | return -1;
246 | }
247 |
248 | list_add_tail(&vip->iplist, &vnet->vip_list);
249 |
250 | return 0;
251 | }
252 |
253 |
254 | /**
255 | * vrrp_net_invalidate_buffer()
256 | * invalidate internal buffer used to stock received pkt
257 | * vnet->__pkt
258 | */
259 | static inline void vrrp_net_invalidate_buffer(struct vrrp_net *vnet)
260 | {
261 | vnet->__pkt.adv.version_type = 0;
262 | }
263 |
264 | /**
265 | * vrrp_net_recv() - read and check a received VRRP pkt advertisement
266 | *
267 | * @return vrrp_pkt_t
268 | */
269 | vrrp_event_t vrrp_net_recv(struct vrrp_net *vnet, const struct vrrp *vrrp)
270 | {
271 | /* fetch pkt data received to buf */
272 | unsigned char buf[IP_MAXPACKET];
273 |
274 | /* read IPvX header values and fill vrrp_recv buffer __pkt */
275 | int payload_pos = 0;
276 | ssize_t len = vnet->pkt_receive(vnet->socket, &vnet->__pkt, buf,
277 | IP_MAXPACKET, &payload_pos);
278 |
279 | /* check len */
280 | if (len == -1) {
281 | log_error("vrid %d :: invalid pkt", vnet->vrid);
282 | return INVALID;
283 | }
284 |
285 | if ((len > vnet->vif.mtu) || (len < vnet->adv_getsize(vnet))) {
286 | log_error("vrid %d :: invalid pkt len", vnet->vrid);
287 | return INVALID;
288 | }
289 |
290 | /* read and check vrrp advertisement pkt */
291 | struct vrrphdr *vrrpkt;
292 |
293 | vrrpkt = (struct vrrphdr *) (buf + payload_pos);
294 |
295 | /* TODO : is this really necessary ?? */
296 | vrrp_net_invalidate_buffer(vnet);
297 |
298 | /* check VRRP pkt size (including VRRP IP address(es) and Auth data) */
299 | unsigned int payload_size =
300 | vnet->__pkt.header.totlen - vnet->__pkt.header.len;
301 |
302 | if ((payload_size < VRRP_PKT_MINSIZE)
303 | || (payload_size > VRRP_PKT_MAXSIZE)) {
304 | log_info
305 | ("vrid %d :: Invalid pkt - Invalid packet size %d, expecting size between %ld and %ld",
306 | vrrp->vrid, payload_size, VRRP_PKT_MINSIZE,
307 | VRRP_PKT_MAXSIZE);
308 | return INVALID;
309 | }
310 |
311 | /* verify ip proto */
312 | if (vnet->__pkt.header.proto != IPPROTO_VRRP) {
313 | log_info("vrid %d :: Invalid pkt - ip proto not valid %d",
314 | vrrp->vrid, vnet->__pkt.header.proto);
315 | return INVALID;
316 | }
317 |
318 | /* verify VRRP version */
319 | if ((vrrpkt->version_type >> 4) != vrrp->version) {
320 | log_info
321 | ("vrid %d :: Invalid pkt - version %d mismatch, expecting %d",
322 | vrrp->vrid, vrrpkt->version_type >> 4, vrrp->version);
323 | return INVALID;
324 | }
325 |
326 | /* TTL must be 255 */
327 | if (vnet->__pkt.header.ttl != VRRP_TTL) {
328 | log_info("vrid %d :: Invalid pkt - TTL isn't %d", vrrp->vrid,
329 | VRRP_TTL);
330 | return INVALID;
331 | }
332 |
333 | /* check if VRID is the same as the current instance */
334 | if (vrrpkt->vrid != vrrp->vrid) {
335 | log_debug("vrid %d :: Invalid pkt - Invalid VRID %d",
336 | vrrp->vrid, vrrpkt->vrid);
337 | return VRID_MISMATCH;
338 | }
339 |
340 | /* verify VRRP checksum */
341 | int chksum = vrrpkt->chksum; /* save checksum */
342 | if (vnet->adv_checksum(vnet, vrrpkt, &vnet->__pkt.s_ipx,
343 | &vnet->__pkt.d_ipx) != chksum) {
344 | log_info("vrid %d :: Invalid pkt - Invalid checksum %x",
345 | vrrp->vrid, chksum);
346 |
347 | return INVALID;
348 | }
349 | /* restore checksum */
350 | vrrpkt->chksum = chksum;
351 |
352 | /* local router is the IP address owner
353 | * (Priority equals 255)
354 | */
355 | if (vrrp->priority == PRIO_OWNER) {
356 | log_info
357 | ("vrid %d :: Invalid pkt - *We* are the owner of IP address(es) (priority %d)",
358 | vrrp->vrid, vrrp->priority);
359 | return INVALID;
360 | }
361 |
362 |
363 | /* Auth type (RFC2338/3768) */
364 | if (vrrp->version != RFC5798) {
365 |
366 | /* auth type must be the same locally configured */
367 | if (vrrpkt->auth_type != vrrp->auth_type) {
368 | log_info
369 | ("vrid %d :: Invalid pkt - Invalid authentication type",
370 | vrrp->vrid);
371 | return INVALID;
372 | }
373 |
374 | /* auth type is simple */
375 | if (vrrpkt->auth_type == SIMPLE) {
376 | uint32_t *auth_data =
377 | (uint32_t *) ((unsigned char *) vrrpkt +
378 | VRRP_PKTHDR_SIZE +
379 | vrrp->naddr * sizeof(uint32_t));
380 | if (memcmp
381 | (auth_data, vrrp->auth_data,
382 | strlen(vrrp->auth_data))
383 | != 0) {
384 | log_info
385 | ("vrid %d :: Invalid pkt - Invalid authentication password",
386 | vrrp->vrid);
387 | return INVALID;
388 | }
389 | }
390 | }
391 |
392 | /* count of IP address(es) and list may be the same
393 | * or generated by the owner
394 | */
395 | if (((vrrpkt->naddr != vrrp->naddr)
396 | || (vnet->vip_compare(vnet, vrrpkt) != 0))
397 | && (vrrpkt->priority != PRIO_OWNER) && (vrrp->version == 2)) {
398 | log_info
399 | ("vrid %d :: Invalid pkt not generated by the owner, drop it",
400 | vrrp->vrid);
401 | return INVALID;
402 | }
403 |
404 | /* advert interval must be the same as the locally configured */
405 | if (vrrpkt->adv_int != vrrp->adv_int) {
406 | log_info
407 | ("vrid %d :: Invalid pkt - Advertisement interval mismatch\n",
408 | vrrp->vrid);
409 | return INVALID;
410 | }
411 |
412 | /* pkt is valid, keep it in internal buffer */
413 | memcpy(&vnet->__pkt.adv, vrrpkt, sizeof(struct vrrphdr));
414 |
415 | return PKT;
416 | }
417 |
418 | /**
419 | * vrrp_net_send - send pkt
420 | */
421 | int vrrp_net_send(const struct vrrp_net *vnet, struct iovec *iov, size_t len)
422 | {
423 | if (iov == NULL) {
424 | log_error("vrid %d :: No data to send !?", vnet->vrid);
425 | return -1;
426 | }
427 |
428 | struct sockaddr_ll device = { 0 };
429 |
430 | device.sll_family = AF_PACKET;
431 | device.sll_ifindex = if_nametoindex(vnet->vif.ifname);
432 |
433 | if (device.sll_ifindex == 0) {
434 | log_error("vrid %d :: if_nametoindex - %m", vnet->vrid);
435 | return -1;
436 | }
437 |
438 | struct msghdr msg = { 0 };
439 |
440 | msg.msg_name = &device;
441 | msg.msg_namelen = sizeof(device);
442 | msg.msg_iov = iov;
443 | msg.msg_iovlen = len;
444 | msg.msg_control = NULL;
445 | msg.msg_controllen = 0;
446 | msg.msg_flags = 0;
447 |
448 | if (sendmsg(vnet->xmit, &msg, 0) < 0) {
449 | log_error("vrid %d :: sendmsg - %m", vnet->vrid);
450 | return -1;
451 | }
452 |
453 | return 0;
454 | }
455 |
--------------------------------------------------------------------------------
/vrrp_net.h:
--------------------------------------------------------------------------------
1 | /*
2 | * vrrp_net.h
3 | *
4 | * Copyright (C) 2014 Arnaud Andre
5 | *
6 | * This file is part of uvrrpd.
7 | *
8 | * uvrrpd is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU General Public License as published by
10 | * the Free Software Foundation, either version 3 of the License, or
11 | * (at your option) any later version.
12 | *
13 | * uvrrpd is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU General Public License
19 | * along with uvrrpd. If not, see .
20 | */
21 |
22 |
23 | #ifndef _VRRP_NET_
24 | #define _VRRP_NET_
25 |
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 | #include
35 |
36 | #include "vrrp_ipx.h"
37 | #include "vrrp_rfc.h"
38 | #include "list.h"
39 |
40 | /* from vrrp.h */
41 | struct vrrp;
42 | typedef enum _vrrp_event_type vrrp_event_t;
43 |
44 | /**
45 | * constants
46 | */
47 | #define IPPROTO_VRRP 112
48 | #define VIP_MAX 255
49 |
50 | #define VRRP_AUTH_SIZE 2*sizeof(uint32_t)
51 | #define VRRP_VIPMAX_SIZE VIP_MAX * sizeof(uint32_t)
52 | #define VRRP_PKTHDR_SIZE sizeof(struct vrrphdr)
53 | #define VRRP_PKT_MINSIZE VRRP_PKTHDR_SIZE + sizeof(uint32_t)
54 | #define VRRP_PKT_MAXSIZE VRRP_PKTHDR_SIZE + VRRP_VIPMAX_SIZE + VRRP_AUTH_SIZE
55 |
56 | #define IPHDR_SIZE sizeof(struct iphdr)
57 |
58 | /**
59 | * struct vrrp_ip - VRRP IPs addresses
60 | */
61 | struct vrrp_ip {
62 | union vrrp_ipx_addr ipx;
63 | uint8_t netmask;
64 | struct list_head iplist;
65 | /* internal buffer for topology update pkt */
66 | struct iovec __topology[3];
67 | };
68 |
69 | /**
70 | * struct vrrp_if - VRRP interface
71 | */
72 | struct vrrp_if {
73 | char *ifname;
74 | int mtu;
75 | union vrrp_ipx_addr ipx;
76 | };
77 |
78 |
79 | /**
80 | * struct vrrp_recv - VRRP buffer recv
81 | */
82 | struct vrrp_recv {
83 | union vrrp_ipx_addr s_ipx;
84 | union vrrp_ipx_addr d_ipx;
85 | struct vrrp_ipx_header header;
86 | struct vrrphdr adv;
87 | };
88 |
89 | #define ip_addr ipx.addr
90 | #define ip_saddr s_ipx.addr
91 | #define ip_daddr d_ipx.addr
92 |
93 | #ifdef HAVE_IP6
94 | #define ip_addr6 ipx.addr6
95 | #define ip_saddr6 s_ipx.addr6
96 | #define ip_daddr6 d_ipx.addr6
97 | #endif /* HAVE_IP6 */
98 |
99 | /**
100 | * struct vrrp_net - VRRP net structure
101 | */
102 | struct vrrp_net {
103 | /* VRRP id */
104 | uint8_t vrid;
105 |
106 | /* VRRP interface */
107 | struct vrrp_if vif;
108 |
109 | /* list of VRRP IP adresses */
110 | struct list_head vip_list;
111 |
112 | /* family */
113 | int family;
114 |
115 | /* count IP addresses */
116 | uint8_t naddr;
117 |
118 | /* listen VRRP socket */
119 | int socket;
120 |
121 | /* xmit VRRP socket */
122 | int xmit;
123 |
124 | /* buffer for received pkt */
125 | struct vrrp_recv __pkt;
126 |
127 | /* buffer for advertisement pkt */
128 | struct iovec __adv[3];
129 |
130 | /* family helper functions */
131 | struct vrrp_ipx *ipx_helper;
132 | };
133 | #define set_sockopt ipx_helper->setsockopt
134 | #define join_mgroup ipx_helper->mgroup
135 | #define vip_compare ipx_helper->viplist_cmp
136 | #define ipx_cmp ipx_helper->cmp
137 | #define pkt_receive ipx_helper->recv
138 | #define adv_checksum ipx_helper->chksum
139 | #define adv_getsize ipx_helper->getsize
140 | #define ipx_to_str ipx_helper->ipx_ntop
141 | #define str_to_ipx ipx_helper->ipx_pton
142 |
143 |
144 | /*
145 | * funcs
146 | */
147 | void vrrp_net_init(struct vrrp_net *vnet);
148 | void vrrp_net_cleanup(struct vrrp_net *vnet);
149 | int vrrp_net_socket(struct vrrp_net *vnet);
150 | int vrrp_net_socket_xmit(struct vrrp_net *vnet);
151 | int vrrp_net_vif_getaddr(struct vrrp_net *vnet);
152 | int vrrp_net_vif_mtu(struct vrrp_net *vnet);
153 | int vrrp_net_vip_set(struct vrrp_net *vnet, const char *ip);
154 | vrrp_event_t vrrp_net_recv(struct vrrp_net *vnet, const struct vrrp *vrrp);
155 | int vrrp_net_send(const struct vrrp_net *vnet, struct iovec *iov, size_t len);
156 |
157 | #endif /* _VRRP_NET_ */
158 |
--------------------------------------------------------------------------------
/vrrp_options.c:
--------------------------------------------------------------------------------
1 | /*
2 | * vrrp_options.c
3 | *
4 | * Copyright (C) 2014 Arnaud Andre
5 | *
6 | * This file is part of uvrrpd.
7 | *
8 | * uvrrpd is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU General Public License as published by
10 | * the Free Software Foundation, either version 3 of the License, or
11 | * (at your option) any later version.
12 | *
13 | * uvrrpd is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU General Public License
19 | * along with uvrrpd. If not, see .
20 | */
21 |
22 | #include
23 | #include
24 | #include
25 | #include
26 |
27 | #include "vrrp.h"
28 | #include "vrrp_net.h"
29 | #include "vrrp_options.h"
30 | #include "common.h"
31 | #include "log.h"
32 |
33 | /* from uvrrpd.c */
34 | extern int background;
35 | extern char *loglevel;
36 | extern char *pidfile_name;
37 | extern char *ctrlfile_name;
38 |
39 | /**
40 | * vrrp_usage()
41 | */
42 | static void vrrp_usage(void)
43 | {
44 | fprintf(stdout,
45 | "Usage: uvrrpd -v vrid -i ifname [OPTIONS] VIP1 [… VIPn]\n\n"
46 | "Mandatory options:\n"
47 | " -v, --vrid vrid Virtual router identifier\n"
48 | " -i, --interface iface Interface\n"
49 | " VIP Virtual IP(s), 1 to 255 VIPs\n\n"
50 | "Optional arguments:\n"
51 | " -p, --priority prio Priority of VRRP Instance, (0-255, default 100)\n"
52 | " -t, --time delay Time interval between advertisements\n"
53 | " Seconds in VRRPv2 (default 1s),\n"
54 | " Centiseconds in VRRPv3 (default 100cs)\n"
55 | " -T, --start-delay delay Use custom delay in INIT state, override masterdown\n"
56 | " timer\n"
57 | " Seconds in VRRPv2 (default 0s),\n"
58 | " Centiseconds in VRRPv3 (default 0cs)\n"
59 | " -P, --preempt on|off Switch preempt (default on)\n"
60 | " -r, --rfc version Specify protocol 'version'\n"
61 | " 2 (VRRPv2, RFC3768) by default,\n"
62 | " 3 (VRRPv3, RFC5798)\n"
63 | #ifdef HAVE_IP6
64 | " -6, --ipv6 IPv6 support, (only in VRRPv3)\n"
65 | #endif /* HAVE_IP6 */
66 | " -a, --auth pass Simple text password (only in VRRPv2)\n"
67 | " -f, --foreground Execute uvrrpd in foreground\n"
68 | " -s, --script Path of hook script (default "stringify(PATH)"/vrrp_switch.sh)\n"
69 | " -F --pidfile name Use alternate pid file 'name'\n"
70 | " Default "stringify(PATHRUN)"/uvrrp_${vrid}.pid\n"
71 | " -C --control name Use alternate control file 'name'\n"
72 | " Default "stringify(PATHRUN)"/uvrrpd_ctrl.${vrid}\n"
73 | " -d, --debug\n" " -h, --help\n");
74 | }
75 |
76 | /**
77 | * vrrp_options() - Parse command line options
78 | */
79 | int vrrp_options(struct vrrp *vrrp, struct vrrp_net *vnet, int argc,
80 | char *argv[])
81 | {
82 | int optc, err;
83 | unsigned long opt; /* strtoul */
84 |
85 | static struct option const opts[] = {
86 | {"vrid", required_argument, 0, 'v'},
87 | {"interface", required_argument, 0, 'i'},
88 | {"priority", required_argument, 0, 'p'},
89 | {"time", required_argument, 0, 't'},
90 | {"start-delay", required_argument, 0, 'T'},
91 | {"preempt", required_argument, 0, 'P'},
92 | {"rfc", required_argument, 0, 'r'},
93 | #ifdef HAVE_IP6
94 | {"ipv6", no_argument, 0, '6'},
95 | #endif /* HAVE_IP6 */
96 | {"auth", required_argument, 0, 'a'},
97 | {"foreground", no_argument, 0, 'f'},
98 | {"script", required_argument, 0, 's'},
99 | {"pidfile", required_argument, 0, 'F'},
100 | {"control", required_argument, 0, 'C'},
101 | {"debug", no_argument, 0, 'd'},
102 | {"help", no_argument, 0, 'h'},
103 | {NULL, 0, 0, 0}
104 | };
105 |
106 | while ((optc =
107 | getopt_long(argc, argv,
108 | #ifdef HAVE_IP6
109 | "v:i:p:t:T:P:r:6a:fs:F:C:dh",
110 | #else
111 | "v:i:p:t:T:P:r:a:fs:F:C:dh",
112 | #endif /* HAVE_IP6 */
113 | opts,
114 |
115 | NULL)) != EOF) {
116 | switch (optc) {
117 |
118 | /* vrid */
119 | case 'v':
120 | err = mystrtoul(&opt, optarg, VRID_MAX);
121 | if (err == -ERANGE || (err == 0 && opt == 0)) {
122 | fprintf(stderr, "1 < vrid < 255\n");
123 | vrrp_usage();
124 | return err;
125 | }
126 | if (err == -EINVAL) {
127 | fprintf(stderr,
128 | "Error parsing \"%s\" as a number\n",
129 | optarg);
130 | vrrp_usage();
131 | return err;
132 | }
133 |
134 | vrrp->vrid = vnet->vrid = (uint8_t) opt;
135 | break;
136 |
137 | /* interface */
138 | case 'i':
139 | vnet->vif.ifname = strndup(optarg, IFNAMSIZ);
140 | if (vnet->vif.ifname == NULL) {
141 | perror("strndup");
142 | return -1;
143 | }
144 | break;
145 |
146 | /* priority */
147 | case 'p':
148 | err = mystrtoul(&opt, optarg, VRRP_PRIO_MAX);
149 | if (err == -ERANGE) {
150 | fprintf(stderr, "0 < priority < 255\n");
151 | vrrp_usage();
152 | return -1;
153 | }
154 | if (err == -EINVAL) {
155 | fprintf(stderr,
156 | "Error parsing \"%s\" as a number\n",
157 | optarg);
158 | vrrp_usage();
159 | return err;
160 | }
161 |
162 | vrrp->priority = (uint8_t) opt;
163 | break;
164 |
165 | /* delay */
166 | case 't':
167 | err = mystrtoul(&opt, optarg, ADVINT_MAX);
168 | if (err == -ERANGE) {
169 | vrrp_usage();
170 | return -1;
171 | }
172 | if (err == -EINVAL) {
173 | fprintf(stderr,
174 | "Error parsing \"%s\" as a number\n",
175 | optarg);
176 | vrrp_usage();
177 | return err;
178 | }
179 |
180 | vrrp->adv_int = (uint16_t) opt;
181 | break;
182 |
183 | /* start delay */
184 | case 'T':
185 | err = mystrtoul(&opt, optarg, ADVINT_MAX);
186 | if (err == -ERANGE) {
187 | vrrp_usage();
188 | return -1;
189 | }
190 | if (err == -EINVAL) {
191 | fprintf(stderr,
192 | "Error parsing \"%s\" as a number\n",
193 | optarg);
194 | vrrp_usage();
195 | return err;
196 | }
197 |
198 | vrrp->start_delay = (uint16_t) opt;
199 | break;
200 |
201 | /* preempt mode */
202 | case 'P':
203 | if (matches(optarg, "on"))
204 | vrrp->preempt = TRUE;
205 | else if (matches(optarg, "off"))
206 | vrrp->preempt = FALSE;
207 | else {
208 | fprintf(stderr,
209 | "preempt mode 'on' or 'off', by default 'on'\n");
210 | vrrp_usage();
211 | return -1;
212 | }
213 | break;
214 |
215 | /* RFC - version */
216 | case 'r':
217 | err = mystrtoul(&opt, optarg, RFC5798);
218 | if (err == -ERANGE || (err == 0 && opt < RFC3768)) {
219 | fprintf(stderr, "Version 2 or 3 : %s\n", optarg);
220 | vrrp_usage();
221 | return -1;
222 | }
223 | if (err == -EINVAL) {
224 | fprintf(stderr,
225 | "Error parsing \"%s\" as a number\n",
226 | optarg);
227 | vrrp_usage();
228 | return err;
229 | }
230 |
231 | vrrp->version = (uint8_t) opt;
232 | break;
233 |
234 | #ifdef HAVE_IP6
235 | /* IPv6 */
236 | case '6': /* Force RFC5798/VRRPv3 */
237 | vrrp->version = RFC5798;
238 | vnet->family = AF_INET6;
239 | break;
240 | #endif /* HAVE_IP6 */
241 |
242 | /* auth */
243 | case 'a': /* only SIMPLE password supported */
244 | if (strlen(optarg) > VRRP_AUTH_PASS_LEN) {
245 | fprintf(stderr,
246 | "Password too long (8 char max)\n");
247 | vrrp_usage();
248 | return -1;
249 | }
250 | vrrp->auth_data = strndup(optarg, VRRP_AUTH_PASS_LEN);
251 | vrrp->auth_type = SIMPLE;
252 | /* hide passwd from ps */
253 | strncpy(optarg, "********", strlen(optarg));
254 | break;
255 |
256 | /* foreground */
257 | case 'f':
258 | background = 0;
259 | break;
260 |
261 |
262 | /* script */
263 | case 's':
264 | vrrp->scriptname = strndup(optarg, VRRP_SCRIPT_MAX);
265 | if (vrrp->scriptname == NULL) {
266 | perror("strndup");
267 | return -1;
268 | }
269 | break;
270 |
271 | /* pidfile */
272 | case 'F':
273 | pidfile_name = strndup(optarg, NAME_MAX + PATH_MAX);
274 | break;
275 |
276 | /* control file (fifo) */
277 | case 'C':
278 | ctrlfile_name = strndup(optarg, NAME_MAX + PATH_MAX);
279 | break;
280 |
281 | /* debug */
282 | case 'd':
283 | loglevel = strndup("debug", 6);
284 | break;
285 |
286 | /* help */
287 | case 'h':
288 | default:
289 | vrrp_usage();
290 | return -1;
291 | break;
292 | }
293 | }
294 |
295 | /* Fetch virtual IP addresses */
296 | if (optind == argc) {
297 | fprintf(stderr, "Specify at least one virtual IP addr !\n");
298 | vrrp_usage();
299 | return -1;
300 | }
301 |
302 | /* Number of IP addresses */
303 | vrrp->naddr = vnet->naddr = argc - optind;
304 |
305 | /* Register vrrp_vip addresses */
306 | while (optind != argc) {
307 | if (vrrp_net_vip_set(vnet, argv[optind]) != 0) {
308 | fprintf(stderr, "Invalid IP\n");
309 | vrrp_usage();
310 | return -1;
311 | }
312 | ++optind;
313 | }
314 |
315 | /* minimal configuration */
316 | if (vrrp->vrid == 0) {
317 | fprintf(stderr, "Specify VRRP id\n");
318 | vrrp_usage();
319 | return -1;
320 | }
321 | if (vnet->vif.ifname == NULL) {
322 | fprintf(stderr, "Specify VRRP interface\n");
323 | vrrp_usage();
324 | return -1;
325 | }
326 |
327 | /* default adv int */
328 | if ((vrrp->version == RFC3768) && (vrrp->adv_int == 0))
329 | vrrp->adv_int = 1;
330 | else if ((vrrp->version == RFC5798) && (vrrp->adv_int == 0))
331 | vrrp->adv_int = 100;
332 |
333 | /* Get IP addresse from interface name */
334 | return vrrp_net_vif_getaddr(vnet);
335 | }
336 |
--------------------------------------------------------------------------------
/vrrp_options.h:
--------------------------------------------------------------------------------
1 | /*
2 | * vrrp_options.h
3 | *
4 | * Copyright (C) 2014 Arnaud Andre
5 | *
6 | * This file is part of uvrrpd.
7 | *
8 | * uvrrpd is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU General Public License as published by
10 | * the Free Software Foundation, either version 3 of the License, or
11 | * (at your option) any later version.
12 | *
13 | * uvrrpd is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU General Public License
19 | * along with uvrrpd. If not, see .
20 | */
21 |
22 | #ifndef _VRRP_OPTIONS_H_
23 | #define _VRRP_OPTIONS_H_
24 |
25 | int vrrp_options(struct vrrp *vrrp, struct vrrp_net *vnet, int argc,
26 | char *argv[]);
27 |
28 | #endif /* _VRRP_OPTIONS_H_ */
29 |
--------------------------------------------------------------------------------
/vrrp_rfc.h:
--------------------------------------------------------------------------------
1 | /*
2 | * vrrp_rfc.h
3 | *
4 | * Copyright (C) 2014 Arnaud Andre
5 | *
6 | * This file is part of uvrrpd.
7 | *
8 | * uvrrpd is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU General Public License as published by
10 | * the Free Software Foundation, either version 3 of the License, or
11 | * (at your option) any later version.
12 | *
13 | * uvrrpd is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU General Public License
19 | * along with uvrrpd. If not, see .
20 | */
21 |
22 | #ifndef _VRRP_RFC_H_
23 | #define _VRRP_RFC_H_
24 |
25 | #include
26 |
27 | /*
28 | * vrrphdr
29 | * Header structure for rfc3768 et rfc5798
30 | */
31 |
32 | struct vrrphdr {
33 | uint8_t version_type; /* 0-3=version, 4-7=type */
34 | uint8_t vrid;
35 | uint8_t priority;
36 | uint8_t naddr;
37 | union {
38 |
39 | /* rfc 3768 */
40 | struct {
41 | uint8_t auth_type;
42 | uint8_t adv_int;
43 | };
44 |
45 | /* rfc 5798 */
46 | uint16_t max_adv_int; /* 0-3=rsvd, 4-5=adv_int */
47 | };
48 | uint16_t chksum;
49 |
50 | /* virtual IPs start here */
51 |
52 | } __attribute__ ((packed));
53 |
54 | #endif /* _VRRP_RFC_H_ */
55 |
--------------------------------------------------------------------------------
/vrrp_state.c:
--------------------------------------------------------------------------------
1 | /*
2 | * vrrp_state.c
3 | *
4 | * Copyright (C) 2014 Arnaud Andre
5 | *
6 | * This file is part of uvrrpd.
7 | *
8 | * uvrrpd is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU General Public License as published by
10 | * the Free Software Foundation, either version 3 of the License, or
11 | * (at your option) any later version.
12 | *
13 | * uvrrpd is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU General Public License
19 | * along with uvrrpd. If not, see .
20 | */
21 |
22 | #include
23 |
24 | #include "vrrp.h"
25 | #include "vrrp_net.h"
26 | #include "vrrp_adv.h"
27 | #include "vrrp_arp.h"
28 | #include "vrrp_na.h"
29 | #include "vrrp_exec.h"
30 |
31 | #include "log.h"
32 | #include "bits.h"
33 | #include "uvrrpd.h"
34 |
35 | extern unsigned long reg;
36 |
37 | /**
38 | * switching state functions
39 | */
40 | static int vrrp_state_goto_master(struct vrrp *vrrp, struct vrrp_net *vnet);
41 | static int vrrp_state_goto_backup(struct vrrp *vrrp, struct vrrp_net *vnet);
42 |
43 | /**
44 | * vrrp_state_init() - Initial state of VRRP instance
45 | *
46 | * Switch to master or backup state
47 | */
48 | int vrrp_state_init(struct vrrp *vrrp, struct vrrp_net *vnet)
49 | {
50 | log_notice("vrid %d :: %s", vrrp->vrid, "init");
51 |
52 | /* Hook init */
53 | vrrp_exec(vrrp, vnet, INIT);
54 |
55 | /* init Master_Adver_Interval */
56 | vrrp->master_adv_int = vrrp->adv_int;
57 | log_debug("%d", vrrp->master_adv_int);
58 |
59 | /* router owns ip address(es) */
60 | if (vrrp->priority == 255) {
61 | log_debug("%s %d :%s", "priority", vrrp->priority,
62 | "router owns VIP address(es)");
63 | return vrrp_state_goto_master(vrrp, vnet);
64 | }
65 |
66 | return vrrp_state_goto_backup(vrrp, vnet);
67 | }
68 |
69 | /**
70 | * vrrp_state_backup() - handle backup state
71 | */
72 | int vrrp_state_backup(struct vrrp *vrrp, struct vrrp_net *vnet)
73 | {
74 | int event = vrrp_listen(vrrp, vnet);
75 | char straddr[INET6_ADDRSTRLEN];
76 |
77 | switch (event) {
78 | case TIMER: /* TIMER expired */
79 | log_notice("vrid %d :: %s", vrrp->vrid,
80 | "masterdown_timer expired");
81 |
82 | vrrp_state_goto_master(vrrp, vnet);
83 | break;
84 |
85 | case PKT: /* PKT received */
86 | /* Must be impossible, invalid received adv buffer */
87 | if (vrrp_adv_get_version(vnet) == 0) {
88 | log_error("vrid %d :: %s", vrrp->vrid,
89 | "recv buffer empty !?");
90 | break;
91 | }
92 |
93 | log_debug("vrid %d :: %s", vrrp->vrid,
94 | "pkt received from current master");
95 | log_debug("vrid %d :: %s:%d %s:%d %s:%s", vrrp->vrid, "prio",
96 | vrrp->priority, "prio recv",
97 | vrrp_adv_get_priority(vnet), "preempt",
98 | STR_PREEMPT(vrrp->preempt));
99 |
100 | /* Priority of received pkt is 0
101 | * => set Master_Down_Timer to skew_time
102 | */
103 | if (vrrp_adv_get_priority(vnet) == 0) {
104 | log_info("vrid %d :: %s", vrrp->vrid,
105 | "receive packet with priority 0");
106 | log_notice("vrid %d :: %s %d", vrrp->vrid,
107 | "set masterdown_timer to skew_time",
108 | SKEW_TIME(vrrp));
109 |
110 | VRRP_SET_SKEW_TIME(vrrp);
111 | break;
112 | }
113 |
114 | /* Master has send its adv pkt, or preemption mode is false
115 | */
116 | if ((vrrp->preempt == FALSE) ||
117 | (vrrp_adv_get_priority(vnet) >= vrrp->priority)) {
118 |
119 | /* RFC5798: Set Master_Adver_Interval to
120 | * Advertisement_Interval
121 | */
122 | if (vrrp->version == RFC5798)
123 | vrrp->master_adv_int =
124 | vrrp_adv_get_advint(vnet);
125 |
126 | VRRP_SET_MASTERDOWN_TIMER(vrrp);
127 | break;
128 | }
129 |
130 | /* Our priority is greater and preemption mode is true
131 | * So we discard advertisement.
132 | * Maybe we'll become Master if Master_Down_Timer expire,
133 | */
134 | log_info("vrid %d :: %s", vrrp->vrid, "discard advertisement");
135 |
136 | break;
137 |
138 | case SIGNAL:
139 | log_debug("vrid %d :: signal", vrrp->vrid);
140 | case CTRL_FIFO:
141 | /* shutdown/reload event ? */
142 | if (test_and_clear_bit(UVRRPD_RELOAD, ®)) {
143 | vrrp_timer_clear(&vrrp->masterdown_timer);
144 | vrrp->state = INIT;
145 | }
146 |
147 | break;
148 |
149 | case VRID_MISMATCH:
150 | /* ignore VRRP pkt with different vrid */
151 | break;
152 |
153 | case INVALID:
154 | log_warning("vrid %d :: %s %s, %s", vrrp->vrid,
155 | "receive an invalid advertisement packet from",
156 | vrrp_adv_addr_to_str(vnet, straddr), "ignore it");
157 |
158 | break;
159 |
160 | default:
161 | log_error("vrid %d :: %s r:%d", vrrp->vrid, "unknown event",
162 | event);
163 | break;
164 | }
165 |
166 | return event;
167 | }
168 |
169 | /**
170 | * vrrp_state_master() - handle master state
171 | */
172 | int vrrp_state_master(struct vrrp *vrrp, struct vrrp_net *vnet)
173 | {
174 | int event = vrrp_listen(vrrp, vnet);
175 |
176 | switch (event) {
177 | case TIMER: /* TIMER expired */
178 | /* adv_timer expired, time to send another */
179 | log_info("vrid %d :: %s", vrrp->vrid, "adv_timer expired");
180 | vrrp_adv_send(vnet);
181 | VRRP_SET_ADV_TIMER(vrrp);
182 | break;
183 |
184 | case PKT: /* PKT received */
185 | /* Must be impossible, invalid adv received buffer */
186 | if (vrrp_adv_get_version(vnet) == 0) {
187 | log_error("vrid %d :: %s", vrrp->vrid,
188 | "recv buffer empty !?");
189 | break;
190 | }
191 |
192 | log_debug("vrid %d :: %s:%d %s:%d %s:%s", vrrp->vrid, "prio",
193 | vrrp->priority, "prio recv",
194 | vrrp_adv_get_priority(vnet), "preempt",
195 | STR_PREEMPT(vrrp->preempt));
196 |
197 | /* Priority of received pkt is 0
198 | * We send an advertisement
199 | * and rearm Adv_timer
200 | */
201 | if (vrrp_adv_get_priority(vnet) == 0) {
202 | log_info("vrid %d :: %s", vrrp->vrid,
203 | "receive packet with priority 0");
204 | vrrp_adv_send(vnet);
205 | VRRP_SET_ADV_TIMER(vrrp);
206 | break;
207 | }
208 |
209 | /* Priority of received pkt is greater than our,
210 | * switch to backup
211 | */
212 | if (vrrp_adv_get_priority(vnet) > vrrp->priority) {
213 |
214 | log_notice("vrid %d :: %s", vrrp->vrid,
215 | "receive packet with higher priority");
216 |
217 | vrrp_state_goto_backup(vrrp, vnet);
218 | break;
219 | }
220 |
221 | /* Priority of received pkt is equal, but
222 | * primary IP address of the sender is greater than
223 | * the local primary IP address,
224 | * switch to backup
225 | */
226 | if (vrrp_adv_get_priority(vnet) == vrrp->priority) {
227 | if (vrrp_adv_addr_cmp(vnet) > 0) {
228 | log_notice("vrid %d :: %s", vrrp->vrid,
229 | "Same priority !");
230 | log_notice("vrid %d :: %s", vrrp->vrid,
231 | "Primary IP address of the sender greater than the local primary address");
232 |
233 | vrrp_state_goto_backup(vrrp, vnet);
234 | break;
235 | }
236 |
237 | log_notice("vrid %d :: %s", vrrp->vrid,
238 | "Same priority !");
239 | log_notice("vrid %d :: %s", vrrp->vrid,
240 | "Local primary address is greater than the primary IP address of the sender");
241 |
242 | }
243 |
244 | /* We have the greatest priority */
245 | log_info("vrid %d :: %s", vrrp->vrid, "discard advertisement");
246 |
247 | break;
248 |
249 | case SIGNAL:
250 | log_debug("vrid %d :: signal", vrrp->vrid);
251 | case CTRL_FIFO:
252 |
253 | /* shutdown/reload event ? */
254 | if (test_and_clear_bit(UVRRPD_RELOAD, ®)) {
255 | vrrp_timer_clear(&vrrp->adv_timer);
256 | vrrp_adv_send_zero(vnet);
257 | /* berk */
258 | vrrp_exec(vrrp, vnet, BACKUP);
259 | vrrp->state = INIT;
260 | }
261 |
262 | break;
263 |
264 | case VRID_MISMATCH:
265 | /* ignore VRRP pkt with different vrid */
266 | break;
267 |
268 | case INVALID:
269 | log_warning("vrid %d :: invalid event", vrrp->vrid);
270 | break;
271 |
272 | default:
273 | log_error("vrid %d :: %s r:%d", vrrp->vrid, "unknown event",
274 | event);
275 | break;
276 | }
277 |
278 | return event;
279 | }
280 |
281 |
282 | /**
283 | * vrrp_state_goto_master() - switch state to master
284 | */
285 | static int vrrp_state_goto_master(struct vrrp *vrrp, struct vrrp_net *vnet)
286 | {
287 | log_notice("vrid %d :: %s -> %s", vrrp->vrid,
288 | STR_STATE(vrrp->state), "master");
289 |
290 | vrrp->state = MASTER;
291 |
292 | vrrp_adv_send(vnet);
293 |
294 | if (vnet->family == AF_INET)
295 | vrrp_arp_send(vnet);
296 | #ifdef HAVE_IP6
297 | else if (vnet->family == AF_INET6)
298 | vrrp_na_send(vnet);
299 | #endif /* HAVE_IP6 */
300 |
301 | /* script */
302 | vrrp_exec(vrrp, vnet, vrrp->state);
303 |
304 | /* reset masterdown_timer && set ADV timer */
305 | vrrp_timer_clear(&vrrp->masterdown_timer);
306 | VRRP_SET_ADV_TIMER(vrrp);
307 |
308 | return 0;
309 | }
310 |
311 |
312 | /**
313 | * vrrp_state_goto_backup() - switch state to backup
314 | */
315 | static int vrrp_state_goto_backup(struct vrrp *vrrp, struct vrrp_net *vnet)
316 | {
317 | log_notice("vrid %d :: %s -> %s", vrrp->vrid,
318 | STR_STATE(vrrp->state), "backup");
319 |
320 | int previous_state = vrrp->state;
321 | vrrp->state = BACKUP;
322 |
323 | log_debug("%s:%s", STR_STATE(previous_state), STR_STATE(vrrp->state));
324 |
325 | /* script */
326 | if (previous_state != INIT)
327 | vrrp_exec(vrrp, vnet, vrrp->state);
328 |
329 | /* RFC5798, use of master_adv_int */
330 | if (vrrp->version == RFC5798) {
331 | if (previous_state == INIT)
332 | vrrp->master_adv_int = vrrp->adv_int;
333 | else if (previous_state == MASTER)
334 | vrrp->master_adv_int = vrrp_adv_get_advint(vnet);
335 | }
336 |
337 | /* clear adv timer && set masterdown_timer */
338 | vrrp_timer_clear(&vrrp->adv_timer);
339 | if ((previous_state == INIT) && (vrrp->start_delay != 0)) {
340 | log_notice("vrid %d :: applying start_delay %d%s",
341 | vrrp->vrid, vrrp->start_delay,
342 | (vrrp->version == 3 ? "cs":"s")
343 | );
344 | VRRP_SET_STARTDELAY_TIMER(vrrp);
345 | }
346 | else
347 | VRRP_SET_MASTERDOWN_TIMER(vrrp);
348 |
349 | log_debug("%d %d", vrrp->master_adv_int,
350 | 3 * vrrp->master_adv_int + SKEW_TIME(vrrp));
351 | return 0;
352 | }
353 |
--------------------------------------------------------------------------------
/vrrp_state.h:
--------------------------------------------------------------------------------
1 | /*
2 | * vrrp_state.h - VRRP state machine
3 | *
4 | * Copyright (C) 2014 Arnaud Andre
5 | *
6 | * This file is part of uvrrpd.
7 | *
8 | * uvrrpd is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU General Public License as published by
10 | * the Free Software Foundation, either version 3 of the License, or
11 | * (at your option) any later version.
12 | *
13 | * uvrrpd is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU General Public License
19 | * along with uvrrpd. If not, see .
20 | */
21 |
22 | #ifndef _VRRP_STATE_H_
23 | #define _VRRP_STATE_H_
24 |
25 | /**
26 | * vrrp_state - VRRP states
27 | */
28 | typedef enum {
29 | INIT,
30 | BACKUP,
31 | MASTER
32 | } vrrp_state;
33 |
34 |
35 | #define STR_STATE(s) (s == INIT ? "init" : \
36 | ((s == BACKUP) ? "backup" : "master"))
37 |
38 | int vrrp_state_init(struct vrrp *vrrp, struct vrrp_net *vnet);
39 | int vrrp_state_master(struct vrrp *vrrp, struct vrrp_net *vnet);
40 | int vrrp_state_backup(struct vrrp *vrrp, struct vrrp_net *vnet);
41 |
42 | #endif /* _VRRP_STATE_H_ */
43 |
--------------------------------------------------------------------------------
/vrrp_switch.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | state=$1
4 | vrid=$2
5 | ifname=$3
6 | priority=$4
7 | adv_int=$5
8 | naddr=$6
9 | family=$7
10 | ips=$8
11 |
12 | echo "state\t\t$state
13 | vrid\t\t$vrid
14 | ifname\t\t$ifname
15 | priority\t$priority
16 | adv_int\t\t$adv_int
17 | naddr\t\t$naddr
18 | ips\t\t$ips" > /tmp/state.vrrp_${vrid}_${ifname}
19 |
20 | interface=${ifname}_${vrid}
21 |
22 | echo $ips
23 |
24 | case "$state" in
25 |
26 | "init" )
27 | # adjust sysctl
28 | sysctl -w net.ipv4.conf.all.rp_filter=0
29 | sysctl -w net.ipv4.conf.all.arp_ignore=1
30 | sysctl -w net.ipv4.conf.all.arp_announce=2
31 | sysctl -w net.ipv4.conf.default.rp_filter=0
32 | sysctl -w net.ipv4.conf.default.arp_ignore=1
33 | sysctl -w net.ipv4.conf.default.arp_announce=2
34 |
35 | if [ -f /proc/net/if_inet6 ]; then
36 | sysctl -w net.ipv6.conf.all.autoconf=0
37 | sysctl -w net.ipv6.conf.all.accept_ra=0
38 | sysctl -w net.ipv6.conf.all.forwarding=1
39 | sysctl -w net.ipv6.conf.default.autoconf=0
40 | sysctl -w net.ipv6.conf.default.accept_ra=0
41 | sysctl -w net.ipv6.conf.default.forwarding=1
42 | fi
43 |
44 | ;;
45 |
46 | "master" )
47 | # create macvlan interface
48 | HEXA_VRID=$(printf %x $vrid)
49 | ip link add link $ifname address 00:00:5E:00:01:$HEXA_VRID $interface type macvlan
50 |
51 | # set virtual ips addresses
52 | OIFS=$IFS
53 | IFS=','
54 |
55 | for ip in $ips; do
56 | ip -$family addr add $ip dev $interface
57 | done
58 | ip link set dev $interface up
59 |
60 | IFS=$OIFS
61 |
62 | ;;
63 |
64 | "backup" )
65 | # destroy macvlan interface
66 | ip link del $interface
67 |
68 | ;;
69 | esac
70 |
71 | exit 0
72 |
--------------------------------------------------------------------------------
/vrrp_timer.c:
--------------------------------------------------------------------------------
1 | /*
2 | * vrrp_timer.c - functions manipulating VRRP timers
3 | *
4 | * Copyright (C) 2014 Arnaud Andre
5 | *
6 | * This file is part of uvrrpd.
7 | *
8 | * uvrrpd is free software: you can redistribute it and/or modify
9 | * it under the terms of the GNU General Public License as published by
10 | * the Free Software Foundation, either version 3 of the License, or
11 | * (at your option) any later version.
12 | *
13 | * uvrrpd is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | * GNU General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU General Public License
19 | * along with uvrrpd. If not, see .
20 | *
21 | *
22 | * These functions use clock_gettime() and CLOCK_MONOTONIC_RAW
23 | * which access to a raw hardware-based time that is not subject to
24 | * NTP adjustements.
25 | */
26 |
27 | #include
28 | #include
29 | #include
30 | #include
31 |
32 | #include "vrrp_timer.h"
33 | #include "log.h"
34 |
35 | /* 1s for timespec operations */
36 | #define NANOUL 1000000000
37 | #define CENTUL 10000000
38 |
39 | /**
40 | * timespec_substract() - substract two timestamp
41 | *
42 | * Subtract the `struct timespec' values X and Y,
43 | * The difference is stored in timespect result.
44 | * @return 1 if the difference is negative, otherwise 0.
45 | */
46 | static inline int timespec_substract(struct timespec *result,
47 | struct timespec *x, struct timespec *y)
48 | {
49 | /* Perform the carry for the later subtraction by updating y. */
50 | if (x->tv_nsec < y->tv_nsec) {
51 | time_t nsec = (y->tv_nsec - x->tv_nsec) / NANOUL + 1;
52 | y->tv_nsec -= NANOUL * nsec;
53 | y->tv_sec += nsec;
54 | }
55 | if (x->tv_nsec - y->tv_nsec > NANOUL) {
56 | time_t nsec = (x->tv_nsec - y->tv_nsec) / NANOUL;
57 | y->tv_nsec += NANOUL * nsec;
58 | y->tv_sec -= nsec;
59 | }
60 |
61 | /* Compute the time remaining to wait.
62 | tv_nsec is certainly positive. */
63 | result->tv_sec = x->tv_sec - y->tv_sec;
64 | result->tv_nsec = x->tv_nsec - y->tv_nsec;
65 |
66 | /* Return 1 if result is negative. */
67 | return x->tv_sec < y->tv_sec;
68 | }
69 |
70 | /**
71 | * vrrp_timer_set() - set timer and reset delta
72 | *
73 | * @delay
74 | * @return -1 if clock_gettime() fail, 0 else
75 | */
76 | int vrrp_timer_set(struct vrrp_timer *timer, time_t delay, long delay_cs)
77 | {
78 | if (clock_gettime(CLOCK_MONOTONIC_RAW, &timer->ts) == -1) {
79 | log_error("clock_gettime: %m");
80 | return -1;
81 | }
82 |
83 | timer->ts.tv_sec += delay;
84 | timer->ts.tv_nsec += delay_cs * CENTUL;
85 |
86 | #ifdef DEBUG
87 | log_debug("delay %ld", delay);
88 | log_debug("delay_cs %ld", delay_cs);
89 |
90 | log_debug("timer->ts.tv_sec %ld", timer->ts.tv_sec);
91 | log_debug("timer->ts.tv_nsec %ld", timer->ts.tv_nsec);
92 | #endif /* DEBUG */
93 |
94 | /* reset delta */
95 | timer->delta.tv_sec = 0;
96 | timer->delta.tv_nsec = 0;
97 |
98 | return 0;
99 | }
100 |
101 | /**
102 | * vrrp_timer_clear() - clear (reset) timer
103 | */
104 | void vrrp_timer_clear(struct vrrp_timer *timer)
105 | {
106 | if (timer == NULL)
107 | return;
108 |
109 | timer->ts.tv_sec = 0;
110 | timer->ts.tv_nsec = 0;
111 | timer->delta.tv_sec = 0;
112 | timer->delta.tv_nsec = 0;
113 | }
114 |
115 | /**
116 | * vrrp_timer_is_running() - determine if a timer is
117 | * currently used
118 | *
119 | * @return 1 if running, 0 else
120 | */
121 | int vrrp_timer_is_running(struct vrrp_timer *timer)
122 | {
123 | if ((timer->ts.tv_sec != 0) || (timer->ts.tv_nsec != 0))
124 | return 1;
125 |
126 | return 0;
127 | }
128 |
129 | /**
130 | * vrrp_timer_update() - update a timer
131 | *
132 | * @return -1 if clock_gettime() failed
133 | * @return ETIME if timer is expired
134 | * @return 0 if timer is successfully updated
135 | */
136 | int vrrp_timer_update(struct vrrp_timer *timer)
137 | {
138 | struct timespec ts;
139 |
140 | if (clock_gettime(CLOCK_MONOTONIC_RAW, &ts) == -1) {
141 | log_error("clock_gettime: %m");
142 | return -1; /* TODO die() */
143 | }
144 |
145 | if (timespec_substract(&timer->delta, &timer->ts, &ts)) {
146 | log_debug("current timer expired");
147 | return 1;
148 | }
149 |
150 | timer->ts.tv_sec = ts.tv_sec + timer->delta.tv_sec;
151 | timer->ts.tv_nsec = ts.tv_nsec + timer->delta.tv_nsec;
152 |
153 | #ifdef DEBUG
154 | log_debug("timer->ts.tv_sec %ld", timer->ts.tv_sec);
155 | log_debug("timer->ts.tv_nsec %ld", timer->ts.tv_nsec);
156 | #endif /* DEBUG */
157 |
158 | return 0;
159 | }
160 |
161 | /**
162 | * vrrp_timer_is_expired() - check if a timer is expired
163 | *
164 | */
165 | int vrrp_timer_is_expired(struct vrrp_timer *timer)
166 | {
167 | if (vrrp_timer_update(timer)
168 | || ((timer->ts.tv_sec <= 0) && (timer->ts.tv_nsec <= 0)))
169 | return 1;
170 |
171 | return 0;
172 | }
173 |
--------------------------------------------------------------------------------
/vrrp_timer.h:
--------------------------------------------------------------------------------
1 | /*
2 | * vrrp_timer.h - functions manipulating VRRP timers
3 | *
4 | * These functions use clock_gettime() and CLOCK_MONOTONIC_RAW
5 | * which use a raw hardware-based time that is not subject to
6 | * NTP adjustements.
7 | *
8 | * Copyright (C) 2014 Arnaud Andre
9 | *
10 | * This file is part of uvrrpd.
11 | *
12 | * uvrrpd is free software: you can redistribute it and/or modify
13 | * it under the terms of the GNU General Public License as published by
14 | * the Free Software Foundation, either version 3 of the License, or
15 | * (at your option) any later version.
16 | *
17 | * uvrrpd is distributed in the hope that it will be useful,
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 | * GNU General Public License for more details.
21 | *
22 | * You should have received a copy of the GNU General Public License
23 | * along with uvrrpd. If not, see .
24 | */
25 |
26 |
27 | #ifndef _VRRP_TIMER_H_
28 | #define _VRRP_TIMER_H_
29 |
30 | #include
31 |
32 | /**
33 | * struct vrrp_timer
34 | *
35 | * @ts timestamp in ns
36 | * @delta time since the last update
37 | */
38 | struct vrrp_timer {
39 | struct timespec ts;
40 | struct timespec delta;
41 | };
42 |
43 | /* prototype functions */
44 | int vrrp_timer_set(struct vrrp_timer *timer, time_t delay, long delay_cs);
45 | void vrrp_timer_clear(struct vrrp_timer *timer);
46 | int vrrp_timer_is_running(struct vrrp_timer *timer);
47 | int vrrp_timer_update(struct vrrp_timer *timer);
48 | int vrrp_timer_is_expired(struct vrrp_timer *timer);
49 |
50 | /* Specific VRRP timer macros */
51 | #define SKEW_TIME( v ) \
52 | ( (256 - v->priority) * \
53 | (v->version==3?v->master_adv_int:1) / 256 )
54 |
55 | #define MASTERDOWN_INT( v ) \
56 | (3 * v->master_adv_int + SKEW_TIME( v ))
57 |
58 | #define VRRP_SET_ADV_TIMER( v ) \
59 | vrrp_timer_set(&v->adv_timer, \
60 | (v->version == 3 ? 0:v->adv_int), \
61 | (v->version == 3 ? v->master_adv_int:0))
62 |
63 | #define VRRP_SET_MASTERDOWN_TIMER( v ) \
64 | vrrp_timer_set(&v->masterdown_timer, \
65 | (v->version == 3 ? 0:MASTERDOWN_INT( v )), \
66 | (v->version == 3 ? MASTERDOWN_INT( v ):0))
67 |
68 | #define VRRP_SET_SKEW_TIME( v ) \
69 | vrrp_timer_set(&v->masterdown_timer, \
70 | (v->version == 3 ? 0:SKEW_TIME( v )), \
71 | (v->version == 3 ? SKEW_TIME( v ):0))
72 |
73 | #define VRRP_SET_STARTDELAY_TIMER( v ) \
74 | vrrp_timer_set(&v->masterdown_timer, \
75 | (v->version == 3 ? 0:v->start_delay), \
76 | (v->version == 3 ? v->start_delay:0))
77 |
78 | #endif /* _VRRP_TIMER_H_ */
79 |
--------------------------------------------------------------------------------