selftest: tests for vfs_fruite file-id behavior
[Samba.git] / ctdb / common / system_freebsd.c
blobe72fbbd28cae84042b44f0f16a5ddac4b3fef376
1 /*
2 ctdb system specific code to manage raw sockets on freebsd
4 Copyright (C) Ronnie Sahlberg 2007
5 Copyright (C) Andrew Tridgell 2007
6 Copyright (C) Marc Dequènes (Duck) 2009
7 Copyright (C) Volker Lendecke 2012
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, see <http://www.gnu.org/licenses/>.
23 This file is a copy of 'common/system_linux.c' adapted for Hurd^W kFreeBSD
24 needs, and inspired by 'common/system_aix.c' for the pcap usage.
27 #include "replace.h"
28 #include "system/network.h"
29 #include "system/filesys.h"
30 #include "system/wait.h"
32 #include "lib/util/debug.h"
33 #include "lib/util/blocking.h"
35 #include "protocol/protocol.h"
37 #include <net/ethernet.h>
38 #include <netinet/ip6.h>
39 #include <net/if_arp.h>
40 #include <pcap.h>
42 #include "common/logging.h"
43 #include "common/system.h"
45 #ifndef ETHERTYPE_IP6
46 #define ETHERTYPE_IP6 0x86dd
47 #endif
50 calculate the tcp checksum for tcp over ipv6
52 static uint16_t tcp_checksum6(uint16_t *data, size_t n, struct ip6_hdr *ip6)
54 uint32_t phdr[2];
55 uint32_t sum = 0;
56 uint16_t sum2;
58 sum += uint16_checksum((uint16_t *)(void *)&ip6->ip6_src, 16);
59 sum += uint16_checksum((uint16_t *)(void *)&ip6->ip6_dst, 16);
61 phdr[0] = htonl(n);
62 phdr[1] = htonl(ip6->ip6_nxt);
63 sum += uint16_checksum((uint16_t *)phdr, 8);
65 sum += uint16_checksum(data, n);
67 sum = (sum & 0xFFFF) + (sum >> 16);
68 sum = (sum & 0xFFFF) + (sum >> 16);
69 sum2 = htons(sum);
70 sum2 = ~sum2;
71 if (sum2 == 0) {
72 return 0xFFFF;
74 return sum2;
78 send gratuitous arp reply after we have taken over an ip address
80 saddr is the address we are trying to claim
81 iface is the interface name we will be using to claim the address
83 int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface)
85 /* FIXME FreeBSD: We don't do gratuitous arp yet */
86 return -1;
91 simple TCP checksum - assumes data is multiple of 2 bytes long
93 static uint16_t tcp_checksum(uint16_t *data, size_t n, struct ip *ip)
95 uint32_t sum = uint16_checksum(data, n);
96 uint16_t sum2;
97 sum += uint16_checksum((uint16_t *)(void *)&ip->ip_src,
98 sizeof(ip->ip_src));
99 sum += uint16_checksum((uint16_t *)(void *)&ip->ip_dst,
100 sizeof(ip->ip_dst));
101 sum += ip->ip_p + n;
102 sum = (sum & 0xFFFF) + (sum >> 16);
103 sum = (sum & 0xFFFF) + (sum >> 16);
104 sum2 = htons(sum);
105 sum2 = ~sum2;
106 if (sum2 == 0) {
107 return 0xFFFF;
109 return sum2;
113 Send tcp segment from the specified IP/port to the specified
114 destination IP/port.
116 This is used to trigger the receiving host into sending its own ACK,
117 which should trigger early detection of TCP reset by the client
118 after IP takeover
120 This can also be used to send RST segments (if rst is true) and also
121 if correct seq and ack numbers are provided.
123 int ctdb_sys_send_tcp(const ctdb_sock_addr *dest,
124 const ctdb_sock_addr *src,
125 uint32_t seq, uint32_t ack, int rst)
127 int s;
128 int ret;
129 uint32_t one = 1;
130 uint16_t tmpport;
131 ctdb_sock_addr *tmpdest;
132 struct {
133 struct ip ip;
134 struct tcphdr tcp;
135 } ip4pkt;
136 struct {
137 struct ip6_hdr ip6;
138 struct tcphdr tcp;
139 } ip6pkt;
140 int saved_errno;
142 switch (src->ip.sin_family) {
143 case AF_INET:
144 ZERO_STRUCT(ip4pkt);
145 ip4pkt.ip.ip_v = 4;
146 ip4pkt.ip.ip_hl = sizeof(ip4pkt.ip)/4;
147 ip4pkt.ip.ip_len = htons(sizeof(ip4pkt));
148 ip4pkt.ip.ip_ttl = 255;
149 ip4pkt.ip.ip_p = IPPROTO_TCP;
150 ip4pkt.ip.ip_src.s_addr = src->ip.sin_addr.s_addr;
151 ip4pkt.ip.ip_dst.s_addr = dest->ip.sin_addr.s_addr;
152 ip4pkt.ip.ip_sum = 0;
154 ip4pkt.tcp.th_sport = src->ip.sin_port;
155 ip4pkt.tcp.th_dport = dest->ip.sin_port;
156 ip4pkt.tcp.th_seq = seq;
157 ip4pkt.tcp.th_ack = ack;
158 ip4pkt.tcp.th_flags = 0;
159 ip4pkt.tcp.th_flags |= TH_ACK;
160 if (rst) {
161 ip4pkt.tcp.th_flags |= TH_RST;
163 ip4pkt.tcp.th_off = sizeof(ip4pkt.tcp)/4;
164 /* this makes it easier to spot in a sniffer */
165 ip4pkt.tcp.th_win = htons(1234);
166 ip4pkt.tcp.th_sum = tcp_checksum((uint16_t *)&ip4pkt.tcp, sizeof(ip4pkt.tcp), &ip4pkt.ip);
168 /* open a raw socket to send this segment from */
169 s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
170 if (s == -1) {
171 DEBUG(DEBUG_CRIT,(__location__ " failed to open raw socket (%s)\n",
172 strerror(errno)));
173 return -1;
176 ret = setsockopt(s, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one));
177 if (ret != 0) {
178 DEBUG(DEBUG_CRIT,(__location__ " failed to setup IP headers (%s)\n",
179 strerror(errno)));
180 close(s);
181 return -1;
184 ret = sendto(s, &ip4pkt, sizeof(ip4pkt), 0,
185 (const struct sockaddr *)&dest->ip,
186 sizeof(dest->ip));
187 saved_errno = errno;
188 close(s);
189 if (ret != sizeof(ip4pkt)) {
190 DEBUG(DEBUG_ERR,
191 ("Failed sendto (%s)\n", strerror(saved_errno)));
192 return -1;
194 break;
195 case AF_INET6:
196 ZERO_STRUCT(ip6pkt);
197 ip6pkt.ip6.ip6_vfc = 0x60;
198 ip6pkt.ip6.ip6_plen = htons(20);
199 ip6pkt.ip6.ip6_nxt = IPPROTO_TCP;
200 ip6pkt.ip6.ip6_hlim = 64;
201 ip6pkt.ip6.ip6_src = src->ip6.sin6_addr;
202 ip6pkt.ip6.ip6_dst = dest->ip6.sin6_addr;
204 ip6pkt.tcp.th_sport = src->ip6.sin6_port;
205 ip6pkt.tcp.th_dport = dest->ip6.sin6_port;
206 ip6pkt.tcp.th_seq = seq;
207 ip6pkt.tcp.th_ack = ack;
208 ip6pkt.tcp.th_flags = 0;
209 ip6pkt.tcp.th_flags |= TH_ACK;
210 if (rst) {
211 ip6pkt.tcp.th_flags |= TH_RST;
213 ip6pkt.tcp.th_off = sizeof(ip6pkt.tcp)/4;
214 /* this makes it easier to spot in a sniffer */
215 ip6pkt.tcp.th_win = htons(1234);
216 ip6pkt.tcp.th_sum = tcp_checksum6((uint16_t *)&ip6pkt.tcp, sizeof(ip6pkt.tcp), &ip6pkt.ip6);
218 s = socket(AF_INET6, SOCK_RAW, IPPROTO_RAW);
219 if (s == -1) {
220 DEBUG(DEBUG_CRIT, (__location__ " Failed to open sending socket\n"));
221 return -1;
224 /* sendto() don't like if the port is set and the socket is
225 in raw mode.
227 tmpdest = discard_const(dest);
228 tmpport = tmpdest->ip6.sin6_port;
230 tmpdest->ip6.sin6_port = 0;
231 ret = sendto(s, &ip6pkt, sizeof(ip6pkt), 0,
232 (const struct sockaddr *)&dest->ip6,
233 sizeof(dest->ip6));
234 saved_errno = errno;
235 tmpdest->ip6.sin6_port = tmpport;
236 close(s);
238 if (ret != sizeof(ip6pkt)) {
239 DEBUG(DEBUG_ERR,
240 ("Failed sendto (%s)\n", strerror(saved_errno)));
241 return -1;
243 break;
245 default:
246 DEBUG(DEBUG_CRIT,(__location__ " not an ipv4/v6 address\n"));
247 return -1;
250 return 0;
254 This function is used to open a raw socket to capture from
256 int ctdb_sys_open_capture_socket(const char *iface, void **private_data)
258 pcap_t *pt;
260 pt=pcap_open_live(iface, 100, 0, 0, NULL);
261 if (pt == NULL) {
262 DEBUG(DEBUG_CRIT,("Failed to open capture device %s\n", iface));
263 return -1;
265 *((pcap_t **)private_data) = pt;
267 return pcap_fileno(pt);
270 /* This function is used to close the capture socket
272 int ctdb_sys_close_capture_socket(void *private_data)
274 pcap_t *pt = (pcap_t *)private_data;
275 pcap_close(pt);
276 return 0;
281 called when the raw socket becomes readable
283 int ctdb_sys_read_tcp_packet(int s, void *private_data,
284 ctdb_sock_addr *src, ctdb_sock_addr *dst,
285 uint32_t *ack_seq, uint32_t *seq,
286 int *rst, uint16_t *window)
288 int ret;
289 #define RCVPKTSIZE 100
290 char pkt[RCVPKTSIZE];
291 struct ether_header *eth;
292 struct ip *ip;
293 struct ip6_hdr *ip6;
294 struct tcphdr *tcp;
296 ret = recv(s, pkt, RCVPKTSIZE, MSG_TRUNC);
297 if (ret < sizeof(*eth)+sizeof(*ip)) {
298 return -1;
301 /* Ethernet */
302 eth = (struct ether_header *)pkt;
304 /* we want either IPv4 or IPv6 */
305 if (ntohs(eth->ether_type) == ETHERTYPE_IP) {
306 /* IP */
307 ip = (struct ip *)(eth+1);
309 /* We only want IPv4 packets */
310 if (ip->ip_v != 4) {
311 return -1;
313 /* Dont look at fragments */
314 if ((ntohs(ip->ip_off)&0x1fff) != 0) {
315 return -1;
317 /* we only want TCP */
318 if (ip->ip_p != IPPROTO_TCP) {
319 return -1;
322 /* make sure its not a short packet */
323 if (offsetof(struct tcphdr, th_ack) + 4 +
324 (ip->ip_hl*4) + sizeof(*eth) > ret) {
325 return -1;
327 /* TCP */
328 tcp = (struct tcphdr *)((ip->ip_hl*4) + (char *)ip);
330 /* tell the caller which one we've found */
331 src->ip.sin_family = AF_INET;
332 src->ip.sin_addr.s_addr = ip->ip_src.s_addr;
333 src->ip.sin_port = tcp->th_sport;
334 dst->ip.sin_family = AF_INET;
335 dst->ip.sin_addr.s_addr = ip->ip_dst.s_addr;
336 dst->ip.sin_port = tcp->th_dport;
337 *ack_seq = tcp->th_ack;
338 *seq = tcp->th_seq;
339 if (window != NULL) {
340 *window = tcp->th_win;
342 if (rst != NULL) {
343 *rst = tcp->th_flags & TH_RST;
346 return 0;
347 } else if (ntohs(eth->ether_type) == ETHERTYPE_IP6) {
348 /* IP6 */
349 ip6 = (struct ip6_hdr *)(eth+1);
351 /* we only want TCP */
352 if (ip6->ip6_nxt != IPPROTO_TCP) {
353 return -1;
356 /* TCP */
357 tcp = (struct tcphdr *)(ip6+1);
359 /* tell the caller which one we've found */
360 src->ip6.sin6_family = AF_INET6;
361 src->ip6.sin6_port = tcp->th_sport;
362 src->ip6.sin6_addr = ip6->ip6_src;
364 dst->ip6.sin6_family = AF_INET6;
365 dst->ip6.sin6_port = tcp->th_dport;
366 dst->ip6.sin6_addr = ip6->ip6_dst;
368 *ack_seq = tcp->th_ack;
369 *seq = tcp->th_seq;
370 if (window != NULL) {
371 *window = tcp->th_win;
373 if (rst != NULL) {
374 *rst = tcp->th_flags & TH_RST;
377 return 0;
380 return -1;
383 bool ctdb_sys_check_iface_exists(const char *iface)
385 /* FIXME FreeBSD: Interface always considered present */
386 return true;
389 int ctdb_get_peer_pid(const int fd, pid_t *peer_pid)
391 /* FIXME FreeBSD: get_peer_pid not implemented */
392 return 1;