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