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