]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_sock.c
pimd: Add debug messages as to why a register packet is rejected.
[mirror_frr.git] / pimd / pim_sock.c
1 /*
2 PIM for Quagga
3 Copyright (C) 2008 Everton da Silva Marques
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; see the file COPYING; if not, write to the
17 Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
18 MA 02110-1301 USA
19
20 */
21
22 #include <zebra.h>
23
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <netinet/in.h>
27 #include <netinet/igmp.h>
28 #include <arpa/inet.h>
29 #include <unistd.h>
30 #include <netdb.h>
31 #include <errno.h>
32
33 #include "log.h"
34 #include "privs.h"
35 #include "if.h"
36 #include "vrf.h"
37 #include "sockopt.h"
38
39 #include "pimd.h"
40 #include "pim_mroute.h"
41 #include "pim_sock.h"
42 #include "pim_str.h"
43 #include "pim_igmp_join.h"
44
45 /* GLOBAL VARS */
46 extern struct zebra_privs_t pimd_privs;
47
48 int
49 pim_socket_raw (int protocol)
50 {
51 int fd;
52
53 if ( pimd_privs.change (ZPRIVS_RAISE) )
54 zlog_err ("pim_sockek_raw: could not raise privs, %s",
55 safe_strerror (errno) );
56
57 fd = socket(AF_INET, SOCK_RAW, protocol);
58
59 if ( pimd_privs.change (ZPRIVS_LOWER) )
60 zlog_err ("pim_socket_raw: could not lower privs, %s",
61 safe_strerror (errno) );
62
63 if (fd < 0) {
64 zlog_warn("Could not create raw socket: errno=%d: %s",
65 errno, safe_strerror(errno));
66 return PIM_SOCK_ERR_SOCKET;
67 }
68
69 return fd;
70 }
71
72 int
73 pim_socket_ip_hdr (int fd)
74 {
75 const int on = 1;
76 int ret;
77
78 if (pimd_privs.change (ZPRIVS_RAISE))
79 zlog_err ("%s: could not raise privs, %s",
80 __PRETTY_FUNCTION__, safe_strerror (errno));
81
82 ret = setsockopt (fd, IPPROTO_IP, IP_HDRINCL, &on, sizeof (on));
83
84 if (pimd_privs.change (ZPRIVS_LOWER))
85 zlog_err ("%s: could not lower privs, %s",
86 __PRETTY_FUNCTION__, safe_strerror (errno));
87
88 return ret;
89 }
90
91 /*
92 * Given a socket and a interface,
93 * Bind that socket to that interface
94 */
95 int
96 pim_socket_bind (int fd, struct interface *ifp)
97 {
98 int ret;
99
100 if (pimd_privs.change (ZPRIVS_RAISE))
101 zlog_err ("%s: could not raise privs, %s",
102 __PRETTY_FUNCTION__, safe_strerror (errno));
103
104 ret = setsockopt (fd, SOL_SOCKET,
105 SO_BINDTODEVICE, ifp->name, strlen (ifp->name));
106
107 if (pimd_privs.change (ZPRIVS_LOWER))
108 zlog_err ("%s: could not lower privs, %s",
109 __PRETTY_FUNCTION__, safe_strerror (errno));
110
111 return ret;
112 }
113
114 int pim_socket_mcast(int protocol, struct in_addr ifaddr, int ifindex, u_char loop)
115 {
116 struct ip_mreqn mreq;
117 int fd;
118
119 fd = pim_socket_raw(protocol);
120 if (fd < 0) {
121 zlog_warn("Could not create multicast socket: errno=%d: %s",
122 errno, safe_strerror(errno));
123 return PIM_SOCK_ERR_SOCKET;
124 }
125
126 #ifdef SO_BINDTODEVICE
127 if (protocol == IPPROTO_PIM)
128 {
129 int ret;
130 struct interface *ifp = NULL;
131
132 ifp = if_lookup_by_index_vrf (ifindex, VRF_DEFAULT);
133
134 ret = pim_socket_bind (fd, ifp);
135 if (ret)
136 {
137 zlog_warn("Could not set fd: %d for interface: %s to device",
138 fd, ifp->name);
139 return PIM_SOCK_ERR_BIND;
140 }
141 }
142 #else
143 /* XXX: use IP_PKTINFO / IP_RECVIF to emulate behaviour? Or change to
144 * only use 1 socket for all interfaces? */
145 #endif
146
147 /* Needed to obtain destination address from recvmsg() */
148 {
149 #if defined(HAVE_IP_PKTINFO)
150 /* Linux and Solaris IP_PKTINFO */
151 int opt = 1;
152 if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt))) {
153 zlog_warn("Could not set IP_PKTINFO on socket fd=%d: errno=%d: %s",
154 fd, errno, safe_strerror(errno));
155 }
156 #elif defined(HAVE_IP_RECVDSTADDR)
157 /* BSD IP_RECVDSTADDR */
158 int opt = 1;
159 if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt))) {
160 zlog_warn("Could not set IP_RECVDSTADDR on socket fd=%d: errno=%d: %s",
161 fd, errno, safe_strerror(errno));
162 }
163 #else
164 zlog_err("%s %s: Missing IP_PKTINFO and IP_RECVDSTADDR: unable to get dst addr from recvmsg()",
165 __FILE__, __PRETTY_FUNCTION__);
166 close(fd);
167 return PIM_SOCK_ERR_DSTADDR;
168 #endif
169 }
170
171
172 /* Set router alert (RFC 2113) for all IGMP messages (RFC 3376 4. Message Formats)*/
173 if (protocol == IPPROTO_IGMP) {
174 char ra[4];
175 ra[0] = 148;
176 ra[1] = 4;
177 ra[2] = 0;
178 ra[3] = 0;
179 if (setsockopt(fd, IPPROTO_IP, IP_OPTIONS, ra, 4)) {
180 zlog_warn("Could not set Router Alert Option on socket fd=%d: errno=%d: %s",
181 fd, errno, safe_strerror(errno));
182 close(fd);
183 return PIM_SOCK_ERR_RA;
184 }
185 }
186
187 {
188 int reuse = 1;
189 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
190 (void *) &reuse, sizeof(reuse))) {
191 zlog_warn("Could not set Reuse Address Option on socket fd=%d: errno=%d: %s",
192 fd, errno, safe_strerror(errno));
193 close(fd);
194 return PIM_SOCK_ERR_REUSE;
195 }
196 }
197
198 {
199 const int MTTL = 1;
200 int ttl = MTTL;
201 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL,
202 (void *) &ttl, sizeof(ttl))) {
203 zlog_warn("Could not set multicast TTL=%d on socket fd=%d: errno=%d: %s",
204 MTTL, fd, errno, safe_strerror(errno));
205 close(fd);
206 return PIM_SOCK_ERR_TTL;
207 }
208 }
209
210 if (setsockopt_ipv4_multicast_loop (fd, loop)) {
211 zlog_warn("Could not %s Multicast Loopback Option on socket fd=%d: errno=%d: %s",
212 loop ? "enable" : "disable",
213 fd, errno, safe_strerror(errno));
214 close(fd);
215 return PIM_SOCK_ERR_LOOP;
216 }
217
218 memset (&mreq, 0, sizeof (mreq));
219 mreq.imr_ifindex = ifindex;
220 if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
221 (void *) &mreq, sizeof(mreq))) {
222 zlog_warn("Could not set Outgoing Interface Option on socket fd=%d: errno=%d: %s",
223 fd, errno, safe_strerror(errno));
224 close(fd);
225 return PIM_SOCK_ERR_IFACE;
226 }
227
228 {
229 long flags;
230
231 flags = fcntl(fd, F_GETFL, 0);
232 if (flags < 0) {
233 zlog_warn("Could not get fcntl(F_GETFL,O_NONBLOCK) on socket fd=%d: errno=%d: %s",
234 fd, errno, safe_strerror(errno));
235 close(fd);
236 return PIM_SOCK_ERR_NONBLOCK_GETFL;
237 }
238
239 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
240 zlog_warn("Could not set fcntl(F_SETFL,O_NONBLOCK) on socket fd=%d: errno=%d: %s",
241 fd, errno, safe_strerror(errno));
242 close(fd);
243 return PIM_SOCK_ERR_NONBLOCK_SETFL;
244 }
245 }
246
247 return fd;
248 }
249
250 int pim_socket_join(int fd, struct in_addr group,
251 struct in_addr ifaddr, ifindex_t ifindex)
252 {
253 int ret;
254
255 #ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX
256 struct ip_mreqn opt;
257 #else
258 struct ip_mreq opt;
259 #endif
260
261 opt.imr_multiaddr = group;
262
263 #ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX
264 opt.imr_address = ifaddr;
265 opt.imr_ifindex = ifindex;
266 #else
267 opt.imr_interface = ifaddr;
268 #endif
269
270 ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &opt, sizeof(opt));
271 if (ret) {
272 char group_str[100];
273 char ifaddr_str[100];
274 if (!inet_ntop(AF_INET, &group, group_str , sizeof(group_str)))
275 sprintf(group_str, "<group?>");
276 if (!inet_ntop(AF_INET, &ifaddr, ifaddr_str , sizeof(ifaddr_str)))
277 sprintf(ifaddr_str, "<ifaddr?>");
278
279 zlog_err("Failure socket joining fd=%d group %s on interface address %s: errno=%d: %s",
280 fd, group_str, ifaddr_str, errno, safe_strerror(errno));
281 return ret;
282 }
283
284 if (PIM_DEBUG_TRACE) {
285 char group_str[100];
286 char ifaddr_str[100];
287 if (!inet_ntop(AF_INET, &group, group_str , sizeof(group_str)))
288 sprintf(group_str, "<group?>");
289 if (!inet_ntop(AF_INET, &ifaddr, ifaddr_str , sizeof(ifaddr_str)))
290 sprintf(ifaddr_str, "<ifaddr?>");
291
292 zlog_debug("Socket fd=%d joined group %s on interface address %s",
293 fd, group_str, ifaddr_str);
294 }
295
296 return ret;
297 }
298
299 int pim_socket_join_source(int fd, ifindex_t ifindex,
300 struct in_addr group_addr,
301 struct in_addr source_addr,
302 const char *ifname)
303 {
304 if (pim_igmp_join_source(fd, ifindex, group_addr, source_addr)) {
305 char group_str[100];
306 char source_str[100];
307 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
308 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
309 zlog_warn("%s: setsockopt(fd=%d) failure for IGMP group %s source %s ifindex %d on interface %s: errno=%d: %s",
310 __PRETTY_FUNCTION__,
311 fd, group_str, source_str, ifindex, ifname,
312 errno, safe_strerror(errno));
313 return -1;
314 }
315
316 return 0;
317 }
318
319 int pim_socket_recvfromto(int fd, uint8_t *buf, size_t len,
320 struct sockaddr_in *from, socklen_t *fromlen,
321 struct sockaddr_in *to, socklen_t *tolen,
322 ifindex_t *ifindex)
323 {
324 struct msghdr msgh;
325 struct cmsghdr *cmsg;
326 struct iovec iov;
327 char cbuf[1000];
328 int err;
329
330 /*
331 * IP_PKTINFO / IP_RECVDSTADDR don't yield sin_port.
332 * Use getsockname() to get sin_port.
333 */
334 if (to) {
335 struct sockaddr_in si;
336 socklen_t si_len = sizeof(si);
337
338 memset (&si, 0, sizeof (si));
339 to->sin_family = AF_INET;
340
341 pim_socket_getsockname(fd, (struct sockaddr *) &si, &si_len);
342
343 to->sin_port = si.sin_port;
344 to->sin_addr = si.sin_addr;
345
346 if (tolen)
347 *tolen = sizeof(si);
348 }
349
350 memset(&msgh, 0, sizeof(struct msghdr));
351 iov.iov_base = buf;
352 iov.iov_len = len;
353 msgh.msg_control = cbuf;
354 msgh.msg_controllen = sizeof(cbuf);
355 msgh.msg_name = from;
356 msgh.msg_namelen = fromlen ? *fromlen : 0;
357 msgh.msg_iov = &iov;
358 msgh.msg_iovlen = 1;
359 msgh.msg_flags = 0;
360
361 err = recvmsg(fd, &msgh, 0);
362 if (err < 0)
363 return err;
364
365 if (fromlen)
366 *fromlen = msgh.msg_namelen;
367
368 for (cmsg = CMSG_FIRSTHDR(&msgh);
369 cmsg != NULL;
370 cmsg = CMSG_NXTHDR(&msgh,cmsg)) {
371
372 #ifdef HAVE_IP_PKTINFO
373 if ((cmsg->cmsg_level == IPPROTO_IP) && (cmsg->cmsg_type == IP_PKTINFO)) {
374 struct in_pktinfo *i = (struct in_pktinfo *) CMSG_DATA(cmsg);
375 if (to)
376 ((struct sockaddr_in *) to)->sin_addr = i->ipi_addr;
377 if (tolen)
378 *tolen = sizeof(struct sockaddr_in);
379 if (ifindex)
380 *ifindex = i->ipi_ifindex;
381
382 if (to && PIM_DEBUG_PACKETS) {
383 char to_str[100];
384 pim_inet4_dump("<to?>", to->sin_addr, to_str, sizeof(to_str));
385 zlog_debug("%s: HAVE_IP_PKTINFO to=%s,%d",
386 __PRETTY_FUNCTION__,
387 to_str, ntohs(to->sin_port));
388 }
389
390 break;
391 }
392 #endif
393
394 #ifdef HAVE_IP_RECVDSTADDR
395 if ((cmsg->cmsg_level == IPPROTO_IP) && (cmsg->cmsg_type == IP_RECVDSTADDR)) {
396 struct in_addr *i = (struct in_addr *) CMSG_DATA(cmsg);
397 if (to)
398 ((struct sockaddr_in *) to)->sin_addr = *i;
399 if (tolen)
400 *tolen = sizeof(struct sockaddr_in);
401
402 if (to && PIM_DEBUG_PACKETS) {
403 char to_str[100];
404 pim_inet4_dump("<to?>", to->sin_addr, to_str, sizeof(to_str));
405 zlog_debug("%s: HAVE_IP_RECVDSTADDR to=%s,%d",
406 __PRETTY_FUNCTION__,
407 to_str, ntohs(to->sin_port));
408 }
409
410 break;
411 }
412 #endif
413
414 #if defined(HAVE_IP_RECVIF) && defined(CMSG_IFINDEX)
415 if (cmsg->cmsg_type == IP_RECVIF)
416 if (ifindex)
417 *ifindex = CMSG_IFINDEX(cmsg);
418 #endif
419
420 } /* for (cmsg) */
421
422 return err; /* len */
423 }
424
425 int pim_socket_mcastloop_get(int fd)
426 {
427 int loop;
428 socklen_t loop_len = sizeof(loop);
429
430 if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
431 &loop, &loop_len)) {
432 int e = errno;
433 zlog_warn("Could not get Multicast Loopback Option on socket fd=%d: errno=%d: %s",
434 fd, errno, safe_strerror(errno));
435 errno = e;
436 return PIM_SOCK_ERR_LOOP;
437 }
438
439 return loop;
440 }
441
442 int pim_socket_getsockname(int fd, struct sockaddr *name, socklen_t *namelen)
443 {
444 if (getsockname(fd, name, namelen)) {
445 int e = errno;
446 zlog_warn("Could not get Socket Name for socket fd=%d: errno=%d: %s",
447 fd, errno, safe_strerror(errno));
448 errno = e;
449 return PIM_SOCK_ERR_NAME;
450 }
451
452 return PIM_SOCK_ERR_NONE;
453 }