1 /*
2  * VRRP ARP handling.
3  * Copyright (C) 2001-2017 Alexandre Cassen
4  * Portions:
5  *     Copyright (C) 2018-2019 Cumulus Networks, Inc.
6  *     Quentin Young
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU General Public License as published by the Free
10  * Software Foundation; either version 2 of the License, or (at your option)
11  * any later version.
12  *
13  * This program is distributed in the hope that it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
16  * more details.
17  *
18  * You should have received a copy of the GNU General Public License along with
19  * this program; see the file COPYING; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 #include <zebra.h>
23 
24 #include <linux/if_packet.h>
25 #include <net/if_arp.h>
26 #include <netinet/if_ether.h>
27 
28 #include "lib/if.h"
29 #include "lib/linklist.h"
30 #include "lib/log.h"
31 #include "lib/memory.h"
32 #include "lib/prefix.h"
33 
34 #include "vrrp.h"
35 #include "vrrp_arp.h"
36 #include "vrrp_debug.h"
37 
38 #define VRRP_LOGPFX "[ARP] "
39 
40 /*
41  * The size of the garp packet buffer should be the large enough to hold the
42  * largest arp packet to be sent + the size of the link layer header for the
43  * corresponding protocol. In this case we hardcode for Ethernet.
44  */
45 #define GARP_BUFFER_SIZE                                                       \
46 	sizeof(struct ether_header) + sizeof(struct arphdr) + 2 * ETH_ALEN     \
47 		+ 2 * sizeof(struct in_addr)
48 
49 /* static vars */
50 static int garp_fd = -1;
51 
52 /* Send the gratuitous ARP message */
vrrp_send_garp(struct interface * ifp,uint8_t * buf,ssize_t pack_len)53 static ssize_t vrrp_send_garp(struct interface *ifp, uint8_t *buf,
54 			      ssize_t pack_len)
55 {
56 	struct sockaddr_ll sll;
57 	ssize_t len;
58 
59 	/* Build the dst device */
60 	memset(&sll, 0, sizeof(sll));
61 	sll.sll_family = AF_PACKET;
62 	sll.sll_protocol = ETH_P_ARP;
63 	sll.sll_ifindex = (int)ifp->ifindex;
64 	sll.sll_halen = ifp->hw_addr_len;
65 	memset(sll.sll_addr, 0xFF, ETH_ALEN);
66 
67 	/* Send packet */
68 	len = sendto(garp_fd, buf, pack_len, 0, (struct sockaddr *)&sll,
69 		     sizeof(sll));
70 
71 	return len;
72 }
73 
74 /* Build a gratuitous ARP message over a specific interface */
vrrp_build_garp(uint8_t * buf,struct interface * ifp,struct in_addr * v4)75 static ssize_t vrrp_build_garp(uint8_t *buf, struct interface *ifp,
76 			       struct in_addr *v4)
77 {
78 	uint8_t *arp_ptr;
79 
80 	if (ifp->hw_addr_len == 0)
81 		return -1;
82 
83 	/* Build Ethernet header */
84 	struct ether_header *eth = (struct ether_header *)buf;
85 
86 	memset(eth->ether_dhost, 0xFF, ETH_ALEN);
87 	memcpy(eth->ether_shost, ifp->hw_addr, ETH_ALEN);
88 	eth->ether_type = htons(ETHERTYPE_ARP);
89 
90 	/* Build ARP payload */
91 	struct arphdr *arph = (struct arphdr *)(buf + ETHER_HDR_LEN);
92 
93 	arph->ar_hrd = htons(HWTYPE_ETHER);
94 	arph->ar_pro = htons(ETHERTYPE_IP);
95 	arph->ar_hln = ifp->hw_addr_len;
96 	arph->ar_pln = sizeof(struct in_addr);
97 	arph->ar_op = htons(ARPOP_REQUEST);
98 	arp_ptr = (uint8_t *)(arph + 1);
99 	/* Source MAC: us */
100 	memcpy(arp_ptr, ifp->hw_addr, ifp->hw_addr_len);
101 	arp_ptr += ifp->hw_addr_len;
102 	/* Source IP: us */
103 	memcpy(arp_ptr, v4, sizeof(struct in_addr));
104 	arp_ptr += sizeof(struct in_addr);
105 	/* Dest MAC: broadcast */
106 	memset(arp_ptr, 0xFF, ETH_ALEN);
107 	arp_ptr += ifp->hw_addr_len;
108 	/* Dest IP: us */
109 	memcpy(arp_ptr, v4, sizeof(struct in_addr));
110 	arp_ptr += sizeof(struct in_addr);
111 
112 	return arp_ptr - buf;
113 }
114 
vrrp_garp_send(struct vrrp_router * r,struct in_addr * v4)115 void vrrp_garp_send(struct vrrp_router *r, struct in_addr *v4)
116 {
117 	struct interface *ifp = r->mvl_ifp;
118 	uint8_t garpbuf[GARP_BUFFER_SIZE];
119 	ssize_t garpbuf_len;
120 	ssize_t sent_len;
121 	char astr[INET_ADDRSTRLEN];
122 
123 	/* If the interface doesn't support ARP, don't try sending */
124 	if (ifp->flags & IFF_NOARP) {
125 		zlog_warn(
126 			VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
127 			"Unable to send gratuitous ARP on %s; has IFF_NOARP",
128 			r->vr->vrid, family2str(r->family), ifp->name);
129 		return;
130 	}
131 
132 	/* Build garp */
133 	garpbuf_len = vrrp_build_garp(garpbuf, ifp, v4);
134 
135 	if (garpbuf_len < 0) {
136 		zlog_warn(
137 			VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
138 			"Unable to send gratuitous ARP on %s; MAC address unknown",
139 			r->vr->vrid, family2str(r->family), ifp->name);
140 		return;
141 	};
142 
143 	/* Send garp */
144 	inet_ntop(AF_INET, v4, astr, sizeof(astr));
145 
146 	DEBUGD(&vrrp_dbg_arp,
147 	       VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
148 	       "Sending gratuitous ARP on %s for %s",
149 	       r->vr->vrid, family2str(r->family), ifp->name, astr);
150 	if (DEBUG_MODE_CHECK(&vrrp_dbg_arp, DEBUG_MODE_ALL))
151 		zlog_hexdump(garpbuf, garpbuf_len);
152 
153 	sent_len = vrrp_send_garp(ifp, garpbuf, garpbuf_len);
154 
155 	if (sent_len < 0)
156 		zlog_warn(VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
157 			  "Error sending gratuitous ARP on %s for %s",
158 			  r->vr->vrid, family2str(r->family), ifp->name, astr);
159 	else
160 		++r->stats.garp_tx_cnt;
161 }
162 
vrrp_garp_send_all(struct vrrp_router * r)163 void vrrp_garp_send_all(struct vrrp_router *r)
164 {
165 	assert(r->family == AF_INET);
166 
167 	struct interface *ifp = r->mvl_ifp;
168 
169 	/* If the interface doesn't support ARP, don't try sending */
170 	if (ifp->flags & IFF_NOARP) {
171 		zlog_warn(
172 			VRRP_LOGPFX VRRP_LOGPFX_VRID VRRP_LOGPFX_FAM
173 			"Unable to send gratuitous ARP on %s; has IFF_NOARP\n",
174 			r->vr->vrid, family2str(r->family), ifp->name);
175 		return;
176 	}
177 
178 	struct listnode *ln;
179 	struct ipaddr *ip;
180 
181 	for (ALL_LIST_ELEMENTS_RO(r->addrs, ln, ip))
182 		vrrp_garp_send(r, &ip->ipaddr_v4);
183 }
184 
185 
vrrp_garp_init(void)186 void vrrp_garp_init(void)
187 {
188 	/* Create the socket descriptor */
189 	/* FIXME: why ETH_P_RARP? */
190 	errno = 0;
191 	frr_with_privs(&vrrp_privs) {
192 		garp_fd = socket(PF_PACKET, SOCK_RAW | SOCK_CLOEXEC,
193 				 htons(ETH_P_RARP));
194 	}
195 
196 	if (garp_fd > 0) {
197 		DEBUGD(&vrrp_dbg_sock,
198 		       VRRP_LOGPFX "Initialized gratuitous ARP socket");
199 		DEBUGD(&vrrp_dbg_arp,
200 		       VRRP_LOGPFX "Initialized gratuitous ARP subsystem");
201 	} else {
202 		zlog_err(VRRP_LOGPFX
203 			 "Error initializing gratuitous ARP subsystem");
204 	}
205 }
206 
vrrp_garp_fini(void)207 void vrrp_garp_fini(void)
208 {
209 	close(garp_fd);
210 	garp_fd = -1;
211 
212 	DEBUGD(&vrrp_dbg_arp,
213 	       VRRP_LOGPFX "Deinitialized gratuitous ARP subsystem");
214 }
215 
vrrp_garp_is_init(void)216 bool vrrp_garp_is_init(void)
217 {
218 	return garp_fd > 0;
219 }
220