1 /*
2  * VRRP packet crafting.
3  * Copyright (C) 2018-2019 Cumulus Networks, Inc.
4  * Quentin Young
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the Free
8  * Software Foundation; either version 2 of the License, or (at your option)
9  * any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; see the file COPYING; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 #ifndef __VRRP_PACKET_H__
21 #define __VRRP_PACKET_H__
22 
23 #include <zebra.h>
24 
25 #include "lib/ipaddr.h"
26 #include "lib/memory.h"
27 #include "lib/prefix.h"
28 
29 #define VRRP_TYPE_ADVERTISEMENT 1
30 
31 /*
32  * Shared header for VRRPv2/v3 packets.
33  */
34 struct vrrp_hdr {
35 	/*
36 	 * H  L H  L
37 	 * 0000 0000
38 	 * ver  type
39 	 */
40 	uint8_t vertype;
41 	uint8_t vrid;
42 	uint8_t priority;
43 	uint8_t naddr;
44 	union {
45 		struct {
46 			uint8_t auth_type;
47 			/* advertisement interval (in sec) */
48 			uint8_t adver_int;
49 		} v2;
50 		struct {
51 			/*
52 			 * advertisement interval (in centiseconds)
53 			 * H  L H          L
54 			 * 0000 000000000000
55 			 * rsvd adver_int
56 			 */
57 			uint16_t adver_int;
58 		} v3;
59 	};
60 	uint16_t chksum;
61 } __attribute__((packed));
62 
63 #define VRRP_HDR_SIZE sizeof(struct vrrp_hdr)
64 
65 struct vrrp_pkt {
66 	struct vrrp_hdr hdr;
67 	/*
68 	 * When used, this is actually an array of one or the other, not an
69 	 * array of union. If N v4 addresses are stored then
70 	 * sizeof(addrs) == N * sizeof(struct in_addr).
71 	 *
72 	 * Under v2, the last 2 entries in this array are the authentication
73 	 * data fields. We don't support auth in v2 so these are always just 8
74 	 * bytes of 0x00.
75 	 */
76 	union {
77 		struct in_addr v4;
78 		struct in6_addr v6;
79 	} addrs[];
80 } __attribute__((packed));
81 
82 #define VRRP_PKT_SIZE(_f, _ver, _naddr)                                        \
83 	({                                                                     \
84 		size_t _asz = ((_f) == AF_INET) ? sizeof(struct in_addr)       \
85 						: sizeof(struct in6_addr);     \
86 		size_t _auth = 2 * sizeof(uint32_t) * (3 - (_ver));            \
87 		sizeof(struct vrrp_hdr) + (_asz * (_naddr)) + _auth;           \
88 	})
89 
90 #define VRRP_MIN_PKT_SIZE_V4 VRRP_PKT_SIZE(AF_INET, 3, 1)
91 #define VRRP_MAX_PKT_SIZE_V4 VRRP_PKT_SIZE(AF_INET, 2, 255)
92 #define VRRP_MIN_PKT_SIZE_V6 VRRP_PKT_SIZE(AF_INET6, 3, 1)
93 #define VRRP_MAX_PKT_SIZE_V6 VRRP_PKT_SIZE(AF_INET6, 3, 255)
94 
95 #define VRRP_MIN_PKT_SIZE VRRP_MIN_PKT_SIZE_V4
96 #define VRRP_MAX_PKT_SIZE VRRP_MAX_PKT_SIZE_V6
97 
98 /*
99  * Builds a VRRP ADVERTISEMENT packet.
100  *
101  * pkt
102  *    Pointer to store pointer to result buffer in
103  *
104  * src
105  *    Source address packet will be transmitted from. This is needed to compute
106  *    the VRRP checksum. The returned packet must be sent in an IP datagram with
107  *    the source address equal to this field, or the checksum will be invalid.
108  *
109  * version
110  *    VRRP version; must be 2 or 3
111  *
112  * vrid
113  *    Virtual Router Identifier
114  *
115  * prio
116  *    Virtual Router Priority
117  *
118  * max_adver_int
119  *    time between ADVERTISEMENTs
120  *
121  * v6
122  *    whether 'ips' is an array of v4 or v6 addresses
123  *
124  * numip
125  *    number of IPvX addresses in 'ips'
126  *
127  * ips
128  *    array of pointer to either struct in_addr (v6 = false) or struct in6_addr
129  *    (v6 = true)
130  */
131 ssize_t vrrp_pkt_adver_build(struct vrrp_pkt **pkt, struct ipaddr *src,
132 			     uint8_t version, uint8_t vrid, uint8_t prio,
133 			     uint16_t max_adver_int, uint8_t numip,
134 			     struct ipaddr **ips);
135 
136 /* free memory allocated by vrrp_pkt_adver_build's pkt arg */
137 void vrrp_pkt_free(struct vrrp_pkt *pkt);
138 
139 /*
140  * Dumps a VRRP ADVERTISEMENT packet to a string.
141  *
142  * Currently only dumps the header.
143  *
144  * buf
145  *    Buffer to store string representation
146  *
147  * buflen
148  *    Size of buf
149  *
150  * pkt
151  *    Packet to dump to a string
152  *
153  * Returns:
154  *    # bytes written to buf
155  */
156 size_t vrrp_pkt_adver_dump(char *buf, size_t buflen, struct vrrp_pkt *pkt);
157 
158 
159 /*
160  * Parses a VRRP packet, checking for illegal or invalid data.
161  *
162  * This function parses both VRRPv2 and VRRPv3 packets. Which version is
163  * expected is determined by the version argument. For example, if version is 3
164  * and the received packet has version field 2 it will fail to parse.
165  *
166  * Note that this function only checks whether the packet itself is a valid
167  * VRRP packet. It is up to the caller to validate whether the VRID is correct,
168  * priority and timer values are correct, etc.
169  *
170  * family
171  *    Address family of received packet
172  *
173  * version
174  *   VRRP version to use for validation
175  *
176  * m
177  *    msghdr containing results of recvmsg() on VRRP router socket
178  *
179  * read
180  *    Return value of recvmsg() on VRRP router socket; must be non-negative
181  *
182  * src
183  *    Pointer to struct ipaddr to store address of datagram sender
184  *
185  * pkt
186  *    Pointer to pointer to set to location of VRRP packet within buf
187  *
188  * errmsg
189  *    Buffer to store human-readable error message in case of error; may be
190  *    NULL, in which case no message will be stored
191  *
192  * errmsg_len
193  *    Size of errmsg
194  *
195  * Returns:
196  *    Size of VRRP packet, or -1 upon error
197  */
198 ssize_t vrrp_pkt_parse_datagram(int family, int version, struct msghdr *m,
199 				size_t read, struct ipaddr *src,
200 				struct vrrp_pkt **pkt, char *errmsg,
201 				size_t errmsg_len);
202 
203 #endif /* __VRRP_PACKET_H__ */
204