]> git.proxmox.com Git - mirror_frr.git/blob - bfdd/linux.c
*: use frr_elevate_privs() (2/2: manual)
[mirror_frr.git] / bfdd / linux.c
1 /*
2 * Linux specific code
3 *
4 * Copyright (C) 2018 Network Device Education Foundation, Inc. ("NetDEF")
5 *
6 * FRR 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
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * FRR is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with FRR; see the file COPYING. If not, write to the Free
18 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 * 02111-1307, USA.
20 */
21
22 #include <zebra.h>
23
24 #ifdef BFD_LINUX
25
26 /* XXX: fix compilation error on Ubuntu 16.04 or older. */
27 #ifndef _UAPI_IPV6_H
28 #define _UAPI_IPV6_H
29 #endif /* _UAPI_IPV6_H */
30
31 #include <linux/filter.h>
32 #include <linux/if_packet.h>
33
34 #include <netinet/if_ether.h>
35
36 #include <net/if.h>
37 #include <sys/ioctl.h>
38
39 #include "bfd.h"
40
41 /* Berkeley Packet filter code to filter out BFD Echo packets.
42 * tcpdump -dd "(udp dst port 3785)"
43 */
44 static struct sock_filter bfd_echo_filter[] = {
45 {0x28, 0, 0, 0x0000000c}, {0x15, 0, 4, 0x000086dd},
46 {0x30, 0, 0, 0x00000014}, {0x15, 0, 11, 0x00000011},
47 {0x28, 0, 0, 0x00000038}, {0x15, 8, 9, 0x00000ec9},
48 {0x15, 0, 8, 0x00000800}, {0x30, 0, 0, 0x00000017},
49 {0x15, 0, 6, 0x00000011}, {0x28, 0, 0, 0x00000014},
50 {0x45, 4, 0, 0x00001fff}, {0xb1, 0, 0, 0x0000000e},
51 {0x48, 0, 0, 0x00000010}, {0x15, 0, 1, 0x00000ec9},
52 {0x6, 0, 0, 0x0000ffff}, {0x6, 0, 0, 0x00000000},
53 };
54
55 /* Berkeley Packet filter code to filter out BFD vxlan packets.
56 * tcpdump -dd "(udp dst port 4789)"
57 */
58 static struct sock_filter bfd_vxlan_filter[] = {
59 {0x28, 0, 0, 0x0000000c}, {0x15, 0, 4, 0x000086dd},
60 {0x30, 0, 0, 0x00000014}, {0x15, 0, 11, 0x00000011},
61 {0x28, 0, 0, 0x00000038}, {0x15, 8, 9, 0x000012b5},
62 {0x15, 0, 8, 0x00000800}, {0x30, 0, 0, 0x00000017},
63 {0x15, 0, 6, 0x00000011}, {0x28, 0, 0, 0x00000014},
64 {0x45, 4, 0, 0x00001fff}, {0xb1, 0, 0, 0x0000000e},
65 {0x48, 0, 0, 0x00000010}, {0x15, 0, 1, 0x000012b5},
66 {0x6, 0, 0, 0x0000ffff}, {0x6, 0, 0, 0x00000000},
67 };
68
69
70 /*
71 * Definitions.
72 */
73 int ptm_bfd_fetch_ifindex(const char *ifname)
74 {
75 struct ifreq ifr;
76
77 if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name))
78 > sizeof(ifr.ifr_name))
79 log_error("interface-to-index: name truncated ('%s' -> '%s')",
80 ifr.ifr_name, ifname);
81
82 if (ioctl(bglobal.bg_shop, SIOCGIFINDEX, &ifr) == -1) {
83 log_error("interface-to-index: %s translation failed: %s",
84 ifname, strerror(errno));
85 return -1;
86 }
87
88 return ifr.ifr_ifindex;
89 }
90
91 void ptm_bfd_fetch_local_mac(const char *ifname, uint8_t *mac)
92 {
93 struct ifreq ifr;
94
95 if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name))
96 > sizeof(ifr.ifr_name))
97 log_error("interface-mac: name truncated ('%s' -> '%s')",
98 ifr.ifr_name, ifname);
99
100 if (ioctl(bglobal.bg_shop, SIOCGIFHWADDR, &ifr) == -1) {
101 log_error("interface-mac: %s MAC retrieval failed: %s", ifname,
102 strerror(errno));
103 return;
104 }
105
106 memcpy(mac, ifr.ifr_hwaddr.sa_data, ETHERNET_ADDRESS_LENGTH);
107 }
108
109
110 /* Was _fetch_portname_from_ifindex() */
111 void fetch_portname_from_ifindex(int ifindex, char *ifname, size_t ifnamelen)
112 {
113 struct ifreq ifr;
114
115 ifname[0] = 0;
116
117 memset(&ifr, 0, sizeof(ifr));
118 ifr.ifr_ifindex = ifindex;
119
120 if (ioctl(bglobal.bg_shop, SIOCGIFNAME, &ifr) == -1) {
121 log_error("index-to-interface: index %d failure: %s", ifindex,
122 strerror(errno));
123 return;
124 }
125
126 if (strlcpy(ifname, ifr.ifr_name, ifnamelen) >= ifnamelen)
127 log_debug("index-to-interface: name truncated '%s' -> '%s'",
128 ifr.ifr_name, ifname);
129 }
130
131 int ptm_bfd_echo_sock_init(void)
132 {
133 int s;
134 struct sock_fprog bpf = {.len = sizeof(bfd_echo_filter)
135 / sizeof(bfd_echo_filter[0]),
136 .filter = bfd_echo_filter};
137
138 s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP));
139 if (s == -1) {
140 log_error("echo-socket: creation failure: %s", strerror(errno));
141 return -1;
142 }
143
144 if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf))
145 == -1) {
146 log_error("echo-socket: setsockopt(SO_ATTACH_FILTER): %s",
147 strerror(errno));
148 close(s);
149 return -1;
150 }
151
152 return s;
153 }
154
155 int ptm_bfd_vxlan_sock_init(void)
156 {
157 int s;
158 struct sock_fprog bpf = {.len = sizeof(bfd_vxlan_filter)
159 / sizeof(bfd_vxlan_filter[0]),
160 .filter = bfd_vxlan_filter};
161
162 s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP));
163 if (s == -1) {
164 log_error("vxlan-socket: creation failure: %s",
165 strerror(errno));
166 return -1;
167 }
168
169 if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf))
170 == -1) {
171 log_error("vxlan-socket: setsockopt(SO_ATTACH_FILTER): %s",
172 strerror(errno));
173 close(s);
174 return -1;
175 }
176
177 return s;
178 }
179
180 int bp_bind_dev(int sd __attribute__((__unused__)),
181 const char *dev __attribute__((__unused__)))
182 {
183 /*
184 * TODO: implement this differently. It is not possible to
185 * SO_BINDTODEVICE after the daemon has dropped its privileges.
186 */
187 #if 0
188 size_t devlen = strlen(dev) + 1;
189
190 if (setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, dev, devlen) == -1) {
191 log_warning("%s: setsockopt(SO_BINDTODEVICE, \"%s\"): %s",
192 __func__, dev, strerror(errno));
193 return -1;
194 }
195 #endif
196
197 return 0;
198 }
199
200 uint16_t udp4_checksum(struct iphdr *iph, uint8_t *buf, int len)
201 {
202 char *ptr;
203 struct udp_psuedo_header pudp_hdr;
204 uint16_t csum;
205
206 pudp_hdr.saddr = iph->saddr;
207 pudp_hdr.daddr = iph->daddr;
208 pudp_hdr.reserved = 0;
209 pudp_hdr.protocol = iph->protocol;
210 pudp_hdr.len = htons(len);
211
212 ptr = XMALLOC(MTYPE_BFDD_TMP, UDP_PSUEDO_HDR_LEN + len);
213 memcpy(ptr, &pudp_hdr, UDP_PSUEDO_HDR_LEN);
214 memcpy(ptr + UDP_PSUEDO_HDR_LEN, buf, len);
215
216 csum = checksum((uint16_t *)ptr, UDP_PSUEDO_HDR_LEN + len);
217 XFREE(MTYPE_BFDD_TMP, ptr);
218 return csum;
219 }
220
221 #endif /* BFD_LINUX */