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
42 #if defined(CONFIG_LINUX_MC_MREQ) || defined(CONFIG_LINUX_MC_MREQ_BIND)
44 * Older kernels support only struct mreq which matches interfaces by their
45 * addresses and thus fails on unnumbered devices. On newer 2.0 kernels
46 * we can use SO_BINDTODEVICE to circumvent this problem.
49 #define MREQ_IFA struct in_addr
50 #define MREQ_GRP struct ip_mreq
51 static inline void fill_mreq_ifa(struct in_addr
*m
, struct iface
*ifa
, UNUSED ip_addr maddr
)
53 set_inaddr(m
, ifa
->addr
->ip
);
56 static inline void fill_mreq_grp(struct ip_mreq
*m
, struct iface
*ifa
, ip_addr maddr
)
59 #ifdef CONFIG_LINUX_MC_MREQ_BIND
60 m
->imr_interface
.s_addr
= INADDR_ANY
;
62 set_inaddr(&m
->imr_interface
, ifa
->addr
->ip
);
64 set_inaddr(&m
->imr_multiaddr
, maddr
);
69 #ifdef CONFIG_LINUX_MC_MREQN
71 * 2.1 and newer kernels use struct mreqn which passes ifindex, so no
72 * problems with unnumbered devices.
75 #ifndef HAVE_STRUCT_IP_MREQN
76 /* Several versions of glibc don't define this structure, so we have to do it ourselves */
79 struct in_addr imr_multiaddr
; /* IP multicast address of group */
80 struct in_addr imr_address
; /* local IP address of interface */
81 int imr_ifindex
; /* Interface index */
85 #define MREQ_IFA struct ip_mreqn
86 #define MREQ_GRP struct ip_mreqn
87 #define fill_mreq_ifa fill_mreq
88 #define fill_mreq_grp fill_mreq
90 static inline fill_mreq(struct ip_mreqn
*m
, struct iface
*ifa
, ip_addr maddr
)
93 m
->imr_ifindex
= ifa
->index
;
94 set_inaddr(&m
->imr_address
, ifa
->addr
->ip
);
95 set_inaddr(&m
->imr_multiaddr
, maddr
);
100 sysio_setup_multicast(sock
*s
)
105 if (setsockopt(s
->fd
, SOL_IP
, IP_MULTICAST_LOOP
, &zero
, sizeof(zero
)) < 0)
106 return "IP_MULTICAST_LOOP";
108 if (setsockopt(s
->fd
, SOL_IP
, IP_MULTICAST_TTL
, &s
->ttl
, sizeof(s
->ttl
)) < 0)
109 return "IP_MULTICAST_TTL";
111 /* This defines where should we send _outgoing_ multicasts */
112 fill_mreq_ifa(&m
, s
->iface
, IPA_NONE
);
113 if (setsockopt(s
->fd
, SOL_IP
, IP_MULTICAST_IF
, &m
, sizeof(m
)) < 0)
114 return "IP_MULTICAST_IF";
116 #if defined(CONFIG_LINUX_MC_MREQ_BIND) || defined(CONFIG_LINUX_MC_MREQN)
119 strcpy(ifr
.ifr_name
, s
->iface
->name
);
120 if (setsockopt(s
->fd
, SOL_SOCKET
, SO_BINDTODEVICE
, &ifr
, sizeof(ifr
)) < 0)
121 return "SO_BINDTODEVICE";
129 sysio_join_group(sock
*s
, ip_addr maddr
)
133 /* And this one sets interface for _receiving_ multicasts from */
134 fill_mreq_grp(&m
, s
->iface
, maddr
);
135 if (setsockopt(s
->fd
, SOL_IP
, IP_ADD_MEMBERSHIP
, &m
, sizeof(m
)) < 0)
136 return "IP_ADD_MEMBERSHIP";
142 sysio_leave_group(sock
*s
, ip_addr maddr
)
146 /* And this one sets interface for _receiving_ multicasts from */
147 fill_mreq_grp(&m
, s
->iface
, maddr
);
148 if (setsockopt(s
->fd
, SOL_IP
, IP_DROP_MEMBERSHIP
, &m
, sizeof(m
)) < 0)
149 return "IP_DROP_MEMBERSHIP";
157 #include <linux/socket.h>
158 #include <linux/tcp.h>
160 /* For the case that we have older kernel headers */
161 /* Copied from Linux kernel file include/linux/tcp.h */
165 #define TCP_MD5SIG 14
166 #define TCP_MD5SIG_MAXKEYLEN 80
169 struct sockaddr_storage tcpm_addr
; /* address associated */
170 __u16 __tcpm_pad1
; /* zero */
171 __u16 tcpm_keylen
; /* key length */
172 __u32 __tcpm_pad2
; /* zero */
173 __u8 tcpm_key
[TCP_MD5SIG_MAXKEYLEN
]; /* key (binary) */
179 sk_set_md5_auth_int(sock
*s
, sockaddr
*sa
, char *passwd
)
181 struct tcp_md5sig md5
;
183 memset(&md5
, 0, sizeof(md5
));
184 memcpy(&md5
.tcpm_addr
, (struct sockaddr
*) sa
, sizeof(*sa
));
188 int len
= strlen(passwd
);
190 if (len
> TCP_MD5SIG_MAXKEYLEN
)
192 log(L_ERR
"MD5 password too long");
196 md5
.tcpm_keylen
= len
;
197 memcpy(&md5
.tcpm_key
, passwd
, len
);
200 int rv
= setsockopt(s
->fd
, IPPROTO_TCP
, TCP_MD5SIG
, &md5
, sizeof(md5
));
204 if (errno
== ENOPROTOOPT
)
205 log(L_ERR
"Kernel does not support TCP MD5 signatures");
207 log(L_ERR
"sk_set_md5_auth_int: setsockopt: %m");