3 Copyright (C) 2008 Everton da Silva Marques
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.
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.
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,
20 $QuaggaId: $Format:%an, %ai, %h$ $
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <netinet/in.h>
28 #include <netinet/igmp.h>
29 #include <arpa/inet.h>
39 #include "pim_mroute.h"
42 #include "pim_igmp_join.h"
45 extern struct zebra_privs_t pimd_privs
;
47 int pim_socket_raw(int protocol
)
51 if ( pimd_privs
.change (ZPRIVS_RAISE
) )
52 zlog_err ("pim_sockek_raw: could not raise privs, %s",
53 safe_strerror (errno
) );
55 fd
= socket(AF_INET
, SOCK_RAW
, protocol
);
57 if ( pimd_privs
.change (ZPRIVS_LOWER
) )
58 zlog_err ("pim_socket_raw: could not lower privs, %s",
59 safe_strerror (errno
) );
62 zlog_warn("Could not create raw socket: errno=%d: %s",
63 errno
, safe_strerror(errno
));
64 return PIM_SOCK_ERR_SOCKET
;
70 int pim_socket_mcast(int protocol
, struct in_addr ifaddr
, int loop
)
74 fd
= pim_socket_raw(protocol
);
76 zlog_warn("Could not create multicast socket: errno=%d: %s",
77 errno
, safe_strerror(errno
));
78 return PIM_SOCK_ERR_SOCKET
;
81 /* Needed to obtain destination address from recvmsg() */
83 #if defined(HAVE_IP_PKTINFO)
84 /* Linux and Solaris IP_PKTINFO */
86 if (setsockopt(fd
, IPPROTO_IP
, IP_PKTINFO
, &opt
, sizeof(opt
))) {
87 zlog_warn("Could not set IP_PKTINFO on socket fd=%d: errno=%d: %s",
88 fd
, errno
, safe_strerror(errno
));
90 #elif defined(HAVE_IP_RECVDSTADDR)
91 /* BSD IP_RECVDSTADDR */
93 if (setsockopt(fd
, IPPROTO_IP
, IP_RECVDSTADDR
, &opt
, sizeof(opt
))) {
94 zlog_warn("Could not set IP_RECVDSTADDR on socket fd=%d: errno=%d: %s",
95 fd
, errno
, safe_strerror(errno
));
98 zlog_err("%s %s: Missing IP_PKTINFO and IP_RECVDSTADDR: unable to get dst addr from recvmsg()",
99 __FILE__
, __PRETTY_FUNCTION__
);
101 return PIM_SOCK_ERR_DSTADDR
;
106 /* Set router alert (RFC 2113) for all IGMP messages (RFC 3376 4. Message Formats)*/
107 if (protocol
== IPPROTO_IGMP
) {
113 if (setsockopt(fd
, IPPROTO_IP
, IP_OPTIONS
, ra
, 4)) {
114 zlog_warn("Could not set Router Alert Option on socket fd=%d: errno=%d: %s",
115 fd
, errno
, safe_strerror(errno
));
117 return PIM_SOCK_ERR_RA
;
123 if (setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
,
124 (void *) &reuse
, sizeof(reuse
))) {
125 zlog_warn("Could not set Reuse Address Option on socket fd=%d: errno=%d: %s",
126 fd
, errno
, safe_strerror(errno
));
128 return PIM_SOCK_ERR_REUSE
;
135 if (setsockopt(fd
, IPPROTO_IP
, IP_MULTICAST_TTL
,
136 (void *) &ttl
, sizeof(ttl
))) {
137 zlog_warn("Could not set multicast TTL=%d on socket fd=%d: errno=%d: %s",
138 MTTL
, fd
, errno
, safe_strerror(errno
));
140 return PIM_SOCK_ERR_TTL
;
144 if (setsockopt(fd
, IPPROTO_IP
, IP_MULTICAST_LOOP
,
145 (void *) &loop
, sizeof(loop
))) {
146 zlog_warn("Could not %s Multicast Loopback Option on socket fd=%d: errno=%d: %s",
147 loop
? "enable" : "disable",
148 fd
, errno
, safe_strerror(errno
));
150 return PIM_SOCK_ERR_LOOP
;
153 if (setsockopt(fd
, IPPROTO_IP
, IP_MULTICAST_IF
,
154 (void *) &ifaddr
, sizeof(ifaddr
))) {
155 zlog_warn("Could not set Outgoing Interface Option on socket fd=%d: errno=%d: %s",
156 fd
, errno
, safe_strerror(errno
));
158 return PIM_SOCK_ERR_IFACE
;
164 flags
= fcntl(fd
, F_GETFL
, 0);
166 zlog_warn("Could not get fcntl(F_GETFL,O_NONBLOCK) on socket fd=%d: errno=%d: %s",
167 fd
, errno
, safe_strerror(errno
));
169 return PIM_SOCK_ERR_NONBLOCK_GETFL
;
172 if (fcntl(fd
, F_SETFL
, flags
| O_NONBLOCK
)) {
173 zlog_warn("Could not set fcntl(F_SETFL,O_NONBLOCK) on socket fd=%d: errno=%d: %s",
174 fd
, errno
, safe_strerror(errno
));
176 return PIM_SOCK_ERR_NONBLOCK_SETFL
;
183 int pim_socket_join(int fd
, struct in_addr group
,
184 struct in_addr ifaddr
, int ifindex
)
188 #ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX
194 opt
.imr_multiaddr
= group
;
196 #ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX
197 opt
.imr_address
= ifaddr
;
198 opt
.imr_ifindex
= ifindex
;
200 opt
.imr_interface
= ifaddr
;
203 ret
= setsockopt(fd
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, &opt
, sizeof(opt
));
206 char ifaddr_str
[100];
207 if (!inet_ntop(AF_INET
, &group
, group_str
, sizeof(group_str
)))
208 sprintf(group_str
, "<group?>");
209 if (!inet_ntop(AF_INET
, &ifaddr
, ifaddr_str
, sizeof(ifaddr_str
)))
210 sprintf(ifaddr_str
, "<ifaddr?>");
212 zlog_err("Failure socket joining fd=%d group %s on interface address %s: errno=%d: %s",
213 fd
, group_str
, ifaddr_str
, errno
, safe_strerror(errno
));
217 if (PIM_DEBUG_TRACE
) {
219 char ifaddr_str
[100];
220 if (!inet_ntop(AF_INET
, &group
, group_str
, sizeof(group_str
)))
221 sprintf(group_str
, "<group?>");
222 if (!inet_ntop(AF_INET
, &ifaddr
, ifaddr_str
, sizeof(ifaddr_str
)))
223 sprintf(ifaddr_str
, "<ifaddr?>");
225 zlog_debug("Socket fd=%d joined group %s on interface address %s",
226 fd
, group_str
, ifaddr_str
);
232 int pim_socket_join_source(int fd
, int ifindex
,
233 struct in_addr group_addr
,
234 struct in_addr source_addr
,
237 if (pim_igmp_join_source(fd
, ifindex
, group_addr
, source_addr
)) {
240 char source_str
[100];
241 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
242 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
243 zlog_warn("%s: setsockopt(fd=%d) failure for IGMP group %s source %s ifindex %d on interface %s: errno=%d: %s",
245 fd
, group_str
, source_str
, ifindex
, ifname
,
246 e
, safe_strerror(e
));
253 int pim_socket_recvfromto(int fd
, uint8_t *buf
, size_t len
,
254 struct sockaddr_in
*from
, socklen_t
*fromlen
,
255 struct sockaddr_in
*to
, socklen_t
*tolen
,
259 struct cmsghdr
*cmsg
;
265 * IP_PKTINFO / IP_RECVDSTADDR don't yield sin_port.
266 * Use getsockname() to get sin_port.
269 struct sockaddr_in si
;
270 socklen_t si_len
= sizeof(si
);
272 ((struct sockaddr_in
*) to
)->sin_family
= AF_INET
;
274 if (pim_socket_getsockname(fd
, (struct sockaddr
*) &si
, &si_len
)) {
275 ((struct sockaddr_in
*) to
)->sin_port
= ntohs(0);
276 ((struct sockaddr_in
*) to
)->sin_addr
.s_addr
= ntohl(0);
279 ((struct sockaddr_in
*) to
)->sin_port
= si
.sin_port
;
280 ((struct sockaddr_in
*) to
)->sin_addr
= si
.sin_addr
;
287 memset(&msgh
, 0, sizeof(struct msghdr
));
290 msgh
.msg_control
= cbuf
;
291 msgh
.msg_controllen
= sizeof(cbuf
);
292 msgh
.msg_name
= from
;
293 msgh
.msg_namelen
= fromlen
? *fromlen
: 0;
298 err
= recvmsg(fd
, &msgh
, 0);
303 *fromlen
= msgh
.msg_namelen
;
305 for (cmsg
= CMSG_FIRSTHDR(&msgh
);
307 cmsg
= CMSG_NXTHDR(&msgh
,cmsg
)) {
309 #ifdef HAVE_IP_PKTINFO
310 if ((cmsg
->cmsg_level
== IPPROTO_IP
) && (cmsg
->cmsg_type
== IP_PKTINFO
)) {
311 struct in_pktinfo
*i
= (struct in_pktinfo
*) CMSG_DATA(cmsg
);
313 ((struct sockaddr_in
*) to
)->sin_addr
= i
->ipi_addr
;
315 *tolen
= sizeof(struct sockaddr_in
);
317 *ifindex
= i
->ipi_ifindex
;
319 if (to
&& PIM_DEBUG_PACKETS
) {
321 pim_inet4_dump("<to?>", to
->sin_addr
, to_str
, sizeof(to_str
));
322 zlog_debug("%s: HAVE_IP_PKTINFO to=%s,%d",
324 to_str
, ntohs(to
->sin_port
));
331 #ifdef HAVE_IP_RECVDSTADDR
332 if ((cmsg
->cmsg_level
== IPPROTO_IP
) && (cmsg
->cmsg_type
== IP_RECVDSTADDR
)) {
333 struct in_addr
*i
= (struct in_addr
*) CMSG_DATA(cmsg
);
335 ((struct sockaddr_in
*) to
)->sin_addr
= *i
;
337 *tolen
= sizeof(struct sockaddr_in
);
339 if (to
&& PIM_DEBUG_PACKETS
) {
341 pim_inet4_dump("<to?>", to
->sin_addr
, to_str
, sizeof(to_str
));
342 zlog_debug("%s: HAVE_IP_RECVDSTADDR to=%s,%d",
344 to_str
, ntohs(to
->sin_port
));
351 #if defined(HAVE_IP_RECVIF) && defined(CMSG_IFINDEX)
352 if (cmsg
->cmsg_type
== IP_RECVIF
)
354 *ifindex
= CMSG_IFINDEX(cmsg
);
359 return err
; /* len */
362 int pim_socket_mcastloop_get(int fd
)
365 socklen_t loop_len
= sizeof(loop
);
367 if (getsockopt(fd
, IPPROTO_IP
, IP_MULTICAST_LOOP
,
370 zlog_warn("Could not get Multicast Loopback Option on socket fd=%d: errno=%d: %s",
371 fd
, errno
, safe_strerror(errno
));
373 return PIM_SOCK_ERR_LOOP
;
379 int pim_socket_getsockname(int fd
, struct sockaddr
*name
, socklen_t
*namelen
)
381 if (getsockname(fd
, name
, namelen
)) {
383 zlog_warn("Could not get Socket Name for socket fd=%d: errno=%d: %s",
384 fd
, errno
, safe_strerror(errno
));
386 return PIM_SOCK_ERR_NAME
;
389 return PIM_SOCK_ERR_NONE
;