2 * BIRD Internet Routing Daemon -- Linux Multicasting and Network Includes
4 * (c) 1998--2000 Martin Mares <mj@ucw.cz>
6 * Can be freely distributed and used under the terms of the GNU GPL.
11 #ifndef IPV6_UNICAST_HOPS
12 /* Needed on glibc 2.0 systems */
13 #include <linux/in6.h>
14 #define CONFIG_IPV6_GLIBC_20
18 set_inaddr(struct in6_addr
*ia
, ip_addr a
)
21 memcpy(ia
, &a
, sizeof(a
));
29 set_inaddr(struct in_addr
*ia
, ip_addr a
)
32 memcpy(&ia
->s_addr
, &a
, sizeof(a
));
36 * Multicasting in Linux systems is a real mess. Not only different kernels
37 * have different interfaces, but also different libc's export it in different
41 static inline char *sysio_mcast_setup(sock
*s
)
45 if (ipa_nonzero(s
->daddr
))
48 #ifdef IP_DEFAULT_MULTICAST_TTL
49 s
->ttl
!= IP_DEFAULT_MULTICAST_TTL
&&
51 setsockopt(s
->fd
, SOL_IP
, IP_MULTICAST_TTL
, &s
->ttl
, sizeof(s
->ttl
)) < 0)
52 return "IP_MULTICAST_TTL";
54 #ifdef IP_DEFAULT_MULTICAST_LOOP
55 IP_DEFAULT_MULTICAST_LOOP
&&
57 setsockopt(s
->fd
, SOL_IP
, IP_MULTICAST_LOOP
, &zero
, sizeof(zero
)) < 0)
58 return "IP_MULTICAST_LOOP";
63 #ifdef CONFIG_LINUX_MC_MREQN
65 * 2.1 and newer kernels use struct mreqn which passes ifindex, so no
66 * problems with unnumbered devices.
69 #ifndef HAVE_STRUCT_IP_MREQN
70 /* Several versions of glibc don't define this structure, so we have to do it ourselves */
73 struct in_addr imr_multiaddr
; /* IP multicast address of group */
74 struct in_addr imr_address
; /* local IP address of interface */
75 int imr_ifindex
; /* Interface index */
79 static inline char *sysio_mcast_join(sock
*s
)
85 if (err
= sysio_mcast_setup(s
))
87 strcpy(ifr
.ifr_name
, s
->iface
->name
);
88 if (setsockopt(s
->fd
, SOL_SOCKET
, SO_BINDTODEVICE
, &ifr
, sizeof(ifr
)) < 0)
89 return "SO_BINDTODEVICE";
90 mreq
.imr_ifindex
= s
->iface
->index
;
91 set_inaddr(&mreq
.imr_address
, s
->iface
->addr
->ip
);
92 set_inaddr(&mreq
.imr_multiaddr
, s
->daddr
);
93 /* This defines where should we send _outgoing_ multicasts */
94 if (ipa_nonzero(s
->daddr
) && setsockopt(s
->fd
, SOL_IP
, IP_MULTICAST_IF
, &mreq
, sizeof(mreq
)) < 0)
95 return "IP_MULTICAST_IF";
96 /* And this one sets interface for _receiving_ multicasts from */
97 if (ipa_nonzero(s
->saddr
) && setsockopt(s
->fd
, SOL_IP
, IP_ADD_MEMBERSHIP
, &mreq
, sizeof(mreq
)) < 0)
98 return "IP_ADD_MEMBERSHIP";
103 #if defined(CONFIG_LINUX_MC_MREQ) || defined(CONFIG_LINUX_MC_MREQ_BIND)
105 * Older kernels support only struct mreq which matches interfaces by their
106 * addresses and thus fails on unnumbered devices. On newer 2.0 kernels
107 * we can use SO_BINDTODEVICE to circumvent this problem.
110 static inline char *sysio_mcast_join(sock
*s
)
113 struct ip_mreq mreq_add
;
116 if (err
= sysio_mcast_setup(s
))
118 set_inaddr(&mreq
, s
->iface
->addr
->ip
);
119 #ifdef CONFIG_LINUX_MC_MREQ_BIND
122 strcpy(ifr
.ifr_name
, s
->iface
->name
);
123 if (setsockopt(s
->fd
, SOL_SOCKET
, SO_BINDTODEVICE
, &ifr
, sizeof(ifr
)) < 0)
124 return "SO_BINDTODEVICE";
125 mreq_add
.imr_interface
.s_addr
= INADDR_ANY
;
128 mreq_add
.imr_interface
= mreq
;
130 set_inaddr(&mreq_add
.imr_multiaddr
, s
->daddr
);
131 /* This defines where should we send _outgoing_ multicasts */
132 if (ipa_nonzero(s
->daddr
) && setsockopt(s
->fd
, SOL_IP
, IP_MULTICAST_IF
, &mreq
, sizeof(mreq
)) < 0)
133 return "IP_MULTICAST_IF";
134 /* And this one sets interface for _receiving_ multicasts from */
135 if (ipa_nonzero(s
->saddr
) && setsockopt(s
->fd
, SOL_IP
, IP_ADD_MEMBERSHIP
, &mreq_add
, sizeof(mreq_add
)) < 0)
136 return "IP_ADD_MEMBERSHIP";
143 #include <linux/socket.h>
144 #include <linux/tcp.h>
146 /* For the case that we have older kernel headers */
147 /* Copied from Linux kernel file include/linux/tcp.h */
151 #define TCP_MD5SIG 14
152 #define TCP_MD5SIG_MAXKEYLEN 80
155 struct sockaddr_storage tcpm_addr
; /* address associated */
156 __u16 __tcpm_pad1
; /* zero */
157 __u16 tcpm_keylen
; /* key length */
158 __u32 __tcpm_pad2
; /* zero */
159 __u8 tcpm_key
[TCP_MD5SIG_MAXKEYLEN
]; /* key (binary) */
165 sk_set_md5_auth_int(sock
*s
, sockaddr
*sa
, char *passwd
)
167 struct tcp_md5sig md5
;
169 memset(&md5
, 0, sizeof(md5
));
170 memcpy(&md5
.tcpm_addr
, (struct sockaddr
*) sa
, sizeof(*sa
));
174 int len
= strlen(passwd
);
176 if (len
> TCP_MD5SIG_MAXKEYLEN
)
178 log(L_ERR
"MD5 password too long");
182 md5
.tcpm_keylen
= len
;
183 memcpy(&md5
.tcpm_key
, passwd
, len
);
186 int rv
= setsockopt(s
->fd
, IPPROTO_TCP
, TCP_MD5SIG
, &md5
, sizeof(md5
));
190 if (errno
== ENOPROTOOPT
)
191 log(L_ERR
"Kernel does not support TCP MD5 signatures");
193 log(L_ERR
"sk_set_md5_auth_int: setsockopt: %m");