]>
Commit | Line | Data |
---|---|---|
67ece6df MM |
1 | /* |
2 | * BIRD Internet Routing Daemon -- Linux Multicasting and Network Includes | |
3 | * | |
f380aa60 | 4 | * (c) 1998--2000 Martin Mares <mj@ucw.cz> |
67ece6df MM |
5 | * |
6 | * Can be freely distributed and used under the terms of the GNU GPL. | |
7 | */ | |
8 | ||
05476c4d OZ |
9 | #ifndef IPV6_MINHOPCOUNT |
10 | #define IPV6_MINHOPCOUNT 73 | |
11 | #endif | |
67ece6df | 12 | |
757cab18 OZ |
13 | #ifndef TCP_MD5SIG_EXT |
14 | #define TCP_MD5SIG_EXT 32 | |
15 | #endif | |
f9c799a0 | 16 | |
757cab18 OZ |
17 | #ifndef TCP_MD5SIG_FLAG_PREFIX |
18 | #define TCP_MD5SIG_FLAG_PREFIX 1 | |
19 | #endif | |
f9c799a0 | 20 | |
757cab18 OZ |
21 | /* We redefine the tcp_md5sig structure with different name to avoid collision with older headers */ |
22 | struct tcp_md5sig_ext { | |
23 | struct sockaddr_storage tcpm_addr; /* Address associated */ | |
24 | u8 tcpm_flags; /* Extension flags */ | |
25 | u8 tcpm_prefixlen; /* Address prefix */ | |
26 | u16 tcpm_keylen; /* Key length */ | |
27 | u32 __tcpm_pad2; /* Zero */ | |
28 | u8 tcpm_key[TCP_MD5SIG_MAXKEYLEN]; /* Key (binary) */ | |
05476c4d | 29 | }; |
f9c799a0 | 30 | |
f9c799a0 | 31 | |
05476c4d OZ |
32 | /* Linux does not care if sa_len is larger than needed */ |
33 | #define SA_LEN(x) sizeof(sockaddr) | |
f9c799a0 | 34 | |
f9c799a0 | 35 | |
05476c4d OZ |
36 | /* |
37 | * Linux IPv4 multicast syscalls | |
38 | */ | |
f9c799a0 | 39 | |
05476c4d OZ |
40 | #define INIT_MREQ4(maddr,ifa) \ |
41 | { .imr_multiaddr = ipa_to_in4(maddr), .imr_ifindex = ifa->index } | |
67ece6df | 42 | |
05476c4d OZ |
43 | static inline int |
44 | sk_setup_multicast4(sock *s) | |
45 | { | |
46 | struct ip_mreqn mr = { .imr_ifindex = s->iface->index }; | |
47 | int ttl = s->ttl; | |
48 | int n = 0; | |
d51aa281 | 49 | |
05476c4d OZ |
50 | /* This defines where should we send _outgoing_ multicasts */ |
51 | if (setsockopt(s->fd, SOL_IP, IP_MULTICAST_IF, &mr, sizeof(mr)) < 0) | |
52 | ERR("IP_MULTICAST_IF"); | |
f9c799a0 | 53 | |
05476c4d OZ |
54 | if (setsockopt(s->fd, SOL_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) |
55 | ERR("IP_MULTICAST_TTL"); | |
d51aa281 | 56 | |
05476c4d OZ |
57 | if (setsockopt(s->fd, SOL_IP, IP_MULTICAST_LOOP, &n, sizeof(n)) < 0) |
58 | ERR("IP_MULTICAST_LOOP"); | |
d51aa281 | 59 | |
05476c4d OZ |
60 | return 0; |
61 | } | |
d51aa281 | 62 | |
05476c4d OZ |
63 | static inline int |
64 | sk_join_group4(sock *s, ip_addr maddr) | |
65 | { | |
66 | struct ip_mreqn mr = INIT_MREQ4(maddr, s->iface); | |
eb5ea6bd | 67 | |
05476c4d OZ |
68 | if (setsockopt(s->fd, SOL_IP, IP_ADD_MEMBERSHIP, &mr, sizeof(mr)) < 0) |
69 | ERR("IP_ADD_MEMBERSHIP"); | |
d51aa281 | 70 | |
05476c4d OZ |
71 | return 0; |
72 | } | |
2b70f074 | 73 | |
05476c4d OZ |
74 | static inline int |
75 | sk_leave_group4(sock *s, ip_addr maddr) | |
2b70f074 | 76 | { |
05476c4d | 77 | struct ip_mreqn mr = INIT_MREQ4(maddr, s->iface); |
2b70f074 | 78 | |
05476c4d OZ |
79 | if (setsockopt(s->fd, SOL_IP, IP_DROP_MEMBERSHIP, &mr, sizeof(mr)) < 0) |
80 | ERR("IP_DROP_MEMBERSHIP"); | |
2b70f074 | 81 | |
05476c4d | 82 | return 0; |
2b70f074 | 83 | } |
353729f5 OZ |
84 | |
85 | ||
05476c4d OZ |
86 | /* |
87 | * Linux IPv4 packet control messages | |
88 | */ | |
353729f5 | 89 | |
353729f5 OZ |
90 | /* Mostly similar to standardized IPv6 code */ |
91 | ||
05476c4d OZ |
92 | #define CMSG4_SPACE_PKTINFO CMSG_SPACE(sizeof(struct in_pktinfo)) |
93 | #define CMSG4_SPACE_TTL CMSG_SPACE(sizeof(int)) | |
353729f5 | 94 | |
05476c4d OZ |
95 | static inline int |
96 | sk_request_cmsg4_pktinfo(sock *s) | |
353729f5 | 97 | { |
05476c4d | 98 | int y = 1; |
70e212f9 | 99 | |
05476c4d OZ |
100 | if (setsockopt(s->fd, SOL_IP, IP_PKTINFO, &y, sizeof(y)) < 0) |
101 | ERR("IP_PKTINFO"); | |
353729f5 | 102 | |
05476c4d | 103 | return 0; |
353729f5 OZ |
104 | } |
105 | ||
05476c4d OZ |
106 | static inline int |
107 | sk_request_cmsg4_ttl(sock *s) | |
353729f5 | 108 | { |
05476c4d | 109 | int y = 1; |
353729f5 | 110 | |
05476c4d OZ |
111 | if (setsockopt(s->fd, SOL_IP, IP_RECVTTL, &y, sizeof(y)) < 0) |
112 | ERR("IP_RECVTTL"); | |
70e212f9 | 113 | |
05476c4d OZ |
114 | return 0; |
115 | } | |
70e212f9 | 116 | |
05476c4d OZ |
117 | static inline void |
118 | sk_process_cmsg4_pktinfo(sock *s, struct cmsghdr *cm) | |
119 | { | |
120 | if (cm->cmsg_type == IP_PKTINFO) | |
70e212f9 | 121 | { |
05476c4d OZ |
122 | struct in_pktinfo *pi = (struct in_pktinfo *) CMSG_DATA(cm); |
123 | s->laddr = ipa_from_in4(pi->ipi_addr); | |
124 | s->lifindex = pi->ipi_ifindex; | |
70e212f9 | 125 | } |
05476c4d | 126 | } |
70e212f9 | 127 | |
05476c4d OZ |
128 | static inline void |
129 | sk_process_cmsg4_ttl(sock *s, struct cmsghdr *cm) | |
130 | { | |
131 | if (cm->cmsg_type == IP_TTL) | |
132 | s->rcv_ttl = * (int *) CMSG_DATA(cm); | |
353729f5 OZ |
133 | } |
134 | ||
05476c4d OZ |
135 | static inline void |
136 | sk_prepare_cmsgs4(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen) | |
353729f5 OZ |
137 | { |
138 | struct cmsghdr *cm; | |
139 | struct in_pktinfo *pi; | |
8945f73d | 140 | int controllen = 0; |
353729f5 | 141 | |
bed41728 OZ |
142 | msg->msg_control = cbuf; |
143 | msg->msg_controllen = cbuflen; | |
353729f5 OZ |
144 | |
145 | cm = CMSG_FIRSTHDR(msg); | |
48e5f32d | 146 | cm->cmsg_level = SOL_IP; |
353729f5 OZ |
147 | cm->cmsg_type = IP_PKTINFO; |
148 | cm->cmsg_len = CMSG_LEN(sizeof(*pi)); | |
8945f73d | 149 | controllen += CMSG_SPACE(sizeof(*pi)); |
353729f5 OZ |
150 | |
151 | pi = (struct in_pktinfo *) CMSG_DATA(cm); | |
353729f5 | 152 | pi->ipi_ifindex = s->iface ? s->iface->index : 0; |
05476c4d OZ |
153 | pi->ipi_spec_dst = ipa_to_in4(s->saddr); |
154 | pi->ipi_addr = ipa_to_in4(IPA_NONE); | |
353729f5 | 155 | |
8945f73d | 156 | msg->msg_controllen = controllen; |
353729f5 | 157 | } |
48e5f32d | 158 | |
646b24d9 | 159 | |
05476c4d OZ |
160 | /* |
161 | * Miscellaneous Linux socket syscalls | |
162 | */ | |
b1b19433 | 163 | |
05476c4d | 164 | int |
fd9f0c06 | 165 | sk_set_md5_auth(sock *s, ip_addr local UNUSED, ip_addr remote, int pxlen, struct iface *ifa, const char *passwd, int setkey UNUSED) |
05476c4d | 166 | { |
757cab18 | 167 | struct tcp_md5sig_ext md5; |
b1b19433 | 168 | |
05476c4d | 169 | memset(&md5, 0, sizeof(md5)); |
a7baa098 | 170 | sockaddr_fill((sockaddr *) &md5.tcpm_addr, s->af, remote, ifa, 0); |
b1b19433 | 171 | |
05476c4d OZ |
172 | if (passwd) |
173 | { | |
174 | int len = strlen(passwd); | |
175 | ||
176 | if (len > TCP_MD5SIG_MAXKEYLEN) | |
a7baa098 | 177 | ERR_MSG("The password for TCP MD5 Signature is too long"); |
b1b19433 | 178 | |
05476c4d OZ |
179 | md5.tcpm_keylen = len; |
180 | memcpy(&md5.tcpm_key, passwd, len); | |
181 | } | |
182 | ||
757cab18 | 183 | if (pxlen < 0) |
05476c4d | 184 | { |
757cab18 OZ |
185 | if (setsockopt(s->fd, SOL_TCP, TCP_MD5SIG, &md5, sizeof(md5)) < 0) |
186 | if (errno == ENOPROTOOPT) | |
187 | ERR_MSG("Kernel does not support TCP MD5 signatures"); | |
188 | else | |
189 | ERR("TCP_MD5SIG"); | |
190 | } | |
191 | else | |
192 | { | |
193 | md5.tcpm_flags = TCP_MD5SIG_FLAG_PREFIX; | |
194 | md5.tcpm_prefixlen = pxlen; | |
195 | ||
196 | if (setsockopt(s->fd, SOL_TCP, TCP_MD5SIG_EXT, &md5, sizeof(md5)) < 0) | |
197 | { | |
198 | if (errno == ENOPROTOOPT) | |
199 | ERR_MSG("Kernel does not support extended TCP MD5 signatures"); | |
200 | else | |
201 | ERR("TCP_MD5SIG_EXT"); | |
202 | } | |
05476c4d | 203 | } |
b1b19433 | 204 | |
05476c4d OZ |
205 | return 0; |
206 | } | |
b1b19433 | 207 | |
05476c4d | 208 | static inline int |
b1b19433 OZ |
209 | sk_set_min_ttl4(sock *s, int ttl) |
210 | { | |
48e5f32d | 211 | if (setsockopt(s->fd, SOL_IP, IP_MINTTL, &ttl, sizeof(ttl)) < 0) |
b1b19433 OZ |
212 | { |
213 | if (errno == ENOPROTOOPT) | |
05476c4d | 214 | ERR_MSG("Kernel does not support IPv4 TTL security"); |
b1b19433 | 215 | else |
05476c4d | 216 | ERR("IP_MINTTL"); |
b1b19433 OZ |
217 | } |
218 | ||
219 | return 0; | |
220 | } | |
221 | ||
05476c4d | 222 | static inline int |
b1b19433 OZ |
223 | sk_set_min_ttl6(sock *s, int ttl) |
224 | { | |
48e5f32d | 225 | if (setsockopt(s->fd, SOL_IPV6, IPV6_MINHOPCOUNT, &ttl, sizeof(ttl)) < 0) |
b1b19433 OZ |
226 | { |
227 | if (errno == ENOPROTOOPT) | |
05476c4d | 228 | ERR_MSG("Kernel does not support IPv6 TTL security"); |
b1b19433 | 229 | else |
05476c4d | 230 | ERR("IPV6_MINHOPCOUNT"); |
b1b19433 OZ |
231 | } |
232 | ||
233 | return 0; | |
234 | } | |
235 | ||
05476c4d OZ |
236 | static inline int |
237 | sk_disable_mtu_disc4(sock *s) | |
238 | { | |
239 | int dont = IP_PMTUDISC_DONT; | |
ef4a50be | 240 | |
05476c4d OZ |
241 | if (setsockopt(s->fd, SOL_IP, IP_MTU_DISCOVER, &dont, sizeof(dont)) < 0) |
242 | ERR("IP_MTU_DISCOVER"); | |
ef4a50be | 243 | |
05476c4d OZ |
244 | return 0; |
245 | } | |
246 | ||
247 | static inline int | |
248 | sk_disable_mtu_disc6(sock *s) | |
249 | { | |
250 | int dont = IPV6_PMTUDISC_DONT; | |
251 | ||
252 | if (setsockopt(s->fd, SOL_IPV6, IPV6_MTU_DISCOVER, &dont, sizeof(dont)) < 0) | |
253 | ERR("IPV6_MTU_DISCOVER"); | |
254 | ||
255 | return 0; | |
256 | } | |
ef4a50be OZ |
257 | |
258 | int sk_priority_control = 7; | |
259 | ||
05476c4d | 260 | static inline int |
ef4a50be OZ |
261 | sk_set_priority(sock *s, int prio) |
262 | { | |
263 | if (setsockopt(s->fd, SOL_SOCKET, SO_PRIORITY, &prio, sizeof(prio)) < 0) | |
05476c4d | 264 | ERR("SO_PRIORITY"); |
ef4a50be OZ |
265 | |
266 | return 0; | |
267 | } | |
05476c4d | 268 |