torture: convert torture_comment() -> torture_result() so we can knownfail flapping...
[Samba/wip.git] / ctdb / common / system_freebsd.c
blob9597a7ac965b27e48a60bf6204efcd80a33067d7
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 "includes.h"
28 #include "system/network.h"
29 #include "system/filesys.h"
30 #include "system/wait.h"
31 #include "../include/ctdb_private.h"
32 #include <net/ethernet.h>
33 #include <netinet/ip6.h>
34 #include <net/if_arp.h>
35 #include <pcap.h>
38 #ifndef ETHERTYPE_IP6
39 #define ETHERTYPE_IP6 0x86dd
40 #endif
43 calculate the tcp checksum for tcp over ipv6
45 static uint16_t tcp_checksum6(uint16_t *data, size_t n, struct ip6_hdr *ip6)
47 uint32_t phdr[2];
48 uint32_t sum = 0;
49 uint16_t sum2;
51 sum += uint16_checksum((uint16_t *)(void *)&ip6->ip6_src, 16);
52 sum += uint16_checksum((uint16_t *)(void *)&ip6->ip6_dst, 16);
54 phdr[0] = htonl(n);
55 phdr[1] = htonl(ip6->ip6_nxt);
56 sum += uint16_checksum((uint16_t *)phdr, 8);
58 sum += uint16_checksum(data, n);
60 sum = (sum & 0xFFFF) + (sum >> 16);
61 sum = (sum & 0xFFFF) + (sum >> 16);
62 sum2 = htons(sum);
63 sum2 = ~sum2;
64 if (sum2 == 0) {
65 return 0xFFFF;
67 return sum2;
71 send gratuitous arp reply after we have taken over an ip address
73 saddr is the address we are trying to claim
74 iface is the interface name we will be using to claim the address
76 int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface)
78 /* FIXME FreeBSD: We dont do gratuitous arp yet */
79 return -1;
84 simple TCP checksum - assumes data is multiple of 2 bytes long
86 static uint16_t tcp_checksum(uint16_t *data, size_t n, struct ip *ip)
88 uint32_t sum = uint16_checksum(data, n);
89 uint16_t sum2;
90 sum += uint16_checksum((uint16_t *)(void *)&ip->ip_src,
91 sizeof(ip->ip_src));
92 sum += uint16_checksum((uint16_t *)(void *)&ip->ip_dst,
93 sizeof(ip->ip_dst));
94 sum += ip->ip_p + n;
95 sum = (sum & 0xFFFF) + (sum >> 16);
96 sum = (sum & 0xFFFF) + (sum >> 16);
97 sum2 = htons(sum);
98 sum2 = ~sum2;
99 if (sum2 == 0) {
100 return 0xFFFF;
102 return sum2;
106 Send tcp segment from the specified IP/port to the specified
107 destination IP/port.
109 This is used to trigger the receiving host into sending its own ACK,
110 which should trigger early detection of TCP reset by the client
111 after IP takeover
113 This can also be used to send RST segments (if rst is true) and also
114 if correct seq and ack numbers are provided.
116 int ctdb_sys_send_tcp(const ctdb_sock_addr *dest,
117 const ctdb_sock_addr *src,
118 uint32_t seq, uint32_t ack, int rst)
120 int s;
121 int ret;
122 uint32_t one = 1;
123 uint16_t tmpport;
124 ctdb_sock_addr *tmpdest;
125 struct {
126 struct ip ip;
127 struct tcphdr tcp;
128 } ip4pkt;
129 struct {
130 struct ip6_hdr ip6;
131 struct tcphdr tcp;
132 } ip6pkt;
134 switch (src->ip.sin_family) {
135 case AF_INET:
136 ZERO_STRUCT(ip4pkt);
137 ip4pkt.ip.ip_v = 4;
138 ip4pkt.ip.ip_hl = sizeof(ip4pkt.ip)/4;
139 ip4pkt.ip.ip_len = htons(sizeof(ip4pkt));
140 ip4pkt.ip.ip_ttl = 255;
141 ip4pkt.ip.ip_p = IPPROTO_TCP;
142 ip4pkt.ip.ip_src.s_addr = src->ip.sin_addr.s_addr;
143 ip4pkt.ip.ip_dst.s_addr = dest->ip.sin_addr.s_addr;
144 ip4pkt.ip.ip_sum = 0;
146 ip4pkt.tcp.th_sport = src->ip.sin_port;
147 ip4pkt.tcp.th_dport = dest->ip.sin_port;
148 ip4pkt.tcp.th_seq = seq;
149 ip4pkt.tcp.th_ack = ack;
150 ip4pkt.tcp.th_flags = 0;
151 ip4pkt.tcp.th_flags |= TH_ACK;
152 if (rst) {
153 ip4pkt.tcp.th_flags |= TH_RST;
155 ip4pkt.tcp.th_off = sizeof(ip4pkt.tcp)/4;
156 /* this makes it easier to spot in a sniffer */
157 ip4pkt.tcp.th_win = htons(1234);
158 ip4pkt.tcp.th_sum = tcp_checksum((uint16_t *)&ip4pkt.tcp, sizeof(ip4pkt.tcp), &ip4pkt.ip);
160 /* open a raw socket to send this segment from */
161 s = socket(AF_INET, SOCK_RAW, htons(IPPROTO_RAW));
162 if (s == -1) {
163 DEBUG(DEBUG_CRIT,(__location__ " failed to open raw socket (%s)\n",
164 strerror(errno)));
165 return -1;
168 ret = setsockopt(s, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one));
169 if (ret != 0) {
170 DEBUG(DEBUG_CRIT,(__location__ " failed to setup IP headers (%s)\n",
171 strerror(errno)));
172 close(s);
173 return -1;
176 set_nonblocking(s);
177 set_close_on_exec(s);
179 ret = sendto(s, &ip4pkt, sizeof(ip4pkt), 0,
180 (const struct sockaddr *)&dest->ip,
181 sizeof(dest->ip));
182 close(s);
183 if (ret != sizeof(ip4pkt)) {
184 DEBUG(DEBUG_CRIT,(__location__ " failed sendto (%s)\n", strerror(errno)));
185 return -1;
187 break;
188 case AF_INET6:
189 ZERO_STRUCT(ip6pkt);
190 ip6pkt.ip6.ip6_vfc = 0x60;
191 ip6pkt.ip6.ip6_plen = htons(20);
192 ip6pkt.ip6.ip6_nxt = IPPROTO_TCP;
193 ip6pkt.ip6.ip6_hlim = 64;
194 ip6pkt.ip6.ip6_src = src->ip6.sin6_addr;
195 ip6pkt.ip6.ip6_dst = dest->ip6.sin6_addr;
197 ip6pkt.tcp.th_sport = src->ip6.sin6_port;
198 ip6pkt.tcp.th_dport = dest->ip6.sin6_port;
199 ip6pkt.tcp.th_seq = seq;
200 ip6pkt.tcp.th_ack = ack;
201 ip6pkt.tcp.th_flags = 0;
202 ip6pkt.tcp.th_flags |= TH_ACK;
203 if (rst) {
204 ip6pkt.tcp.th_flags |= TH_RST;
206 ip6pkt.tcp.th_off = sizeof(ip6pkt.tcp)/4;
207 /* this makes it easier to spot in a sniffer */
208 ip6pkt.tcp.th_win = htons(1234);
209 ip6pkt.tcp.th_sum = tcp_checksum6((uint16_t *)&ip6pkt.tcp, sizeof(ip6pkt.tcp), &ip6pkt.ip6);
211 s = socket(PF_INET6, SOCK_RAW, IPPROTO_RAW);
212 if (s == -1) {
213 DEBUG(DEBUG_CRIT, (__location__ " Failed to open sending socket\n"));
214 return -1;
217 /* sendto() dont like if the port is set and the socket is
218 in raw mode.
220 tmpdest = discard_const(dest);
221 tmpport = tmpdest->ip6.sin6_port;
223 tmpdest->ip6.sin6_port = 0;
224 ret = sendto(s, &ip6pkt, sizeof(ip6pkt), 0,
225 (const struct sockaddr *)&dest->ip6,
226 sizeof(dest->ip6));
227 tmpdest->ip6.sin6_port = tmpport;
228 close(s);
230 if (ret != sizeof(ip6pkt)) {
231 DEBUG(DEBUG_CRIT,(__location__ " failed sendto (%s)\n", strerror(errno)));
232 return -1;
234 break;
236 default:
237 DEBUG(DEBUG_CRIT,(__location__ " not an ipv4/v6 address\n"));
238 return -1;
241 return 0;
245 This function is used to open a raw socket to capture from
247 int ctdb_sys_open_capture_socket(const char *iface, void **private_data)
249 pcap_t *pt;
251 pt=pcap_open_live(iface, 100, 0, 0, NULL);
252 if (pt == NULL) {
253 DEBUG(DEBUG_CRIT,("Failed to open capture device %s\n", iface));
254 return -1;
256 *((pcap_t **)private_data) = pt;
258 return pcap_fileno(pt);
261 /* This function is used to close the capture socket
263 int ctdb_sys_close_capture_socket(void *private_data)
265 pcap_t *pt = (pcap_t *)private_data;
266 pcap_close(pt);
267 return 0;
272 called when the raw socket becomes readable
274 int ctdb_sys_read_tcp_packet(int s, void *private_data,
275 ctdb_sock_addr *src, ctdb_sock_addr *dst,
276 uint32_t *ack_seq, uint32_t *seq)
278 int ret;
279 #define RCVPKTSIZE 100
280 char pkt[RCVPKTSIZE];
281 struct ether_header *eth;
282 struct ip *ip;
283 struct ip6_hdr *ip6;
284 struct tcphdr *tcp;
286 ret = recv(s, pkt, RCVPKTSIZE, MSG_TRUNC);
287 if (ret < sizeof(*eth)+sizeof(*ip)) {
288 return -1;
291 /* Ethernet */
292 eth = (struct ether_header *)pkt;
294 /* we want either IPv4 or IPv6 */
295 if (ntohs(eth->ether_type) == ETHERTYPE_IP) {
296 /* IP */
297 ip = (struct ip *)(eth+1);
299 /* We only want IPv4 packets */
300 if (ip->ip_v != 4) {
301 return -1;
303 /* Dont look at fragments */
304 if ((ntohs(ip->ip_off)&0x1fff) != 0) {
305 return -1;
307 /* we only want TCP */
308 if (ip->ip_p != IPPROTO_TCP) {
309 return -1;
312 /* make sure its not a short packet */
313 if (offsetof(struct tcphdr, th_ack) + 4 +
314 (ip->ip_hl*4) + sizeof(*eth) > ret) {
315 return -1;
317 /* TCP */
318 tcp = (struct tcphdr *)((ip->ip_hl*4) + (char *)ip);
320 /* tell the caller which one we've found */
321 src->ip.sin_family = AF_INET;
322 src->ip.sin_addr.s_addr = ip->ip_src.s_addr;
323 src->ip.sin_port = tcp->th_sport;
324 dst->ip.sin_family = AF_INET;
325 dst->ip.sin_addr.s_addr = ip->ip_dst.s_addr;
326 dst->ip.sin_port = tcp->th_dport;
327 *ack_seq = tcp->th_ack;
328 *seq = tcp->th_seq;
330 return 0;
331 } else if (ntohs(eth->ether_type) == ETHERTYPE_IP6) {
332 /* IP6 */
333 ip6 = (struct ip6_hdr *)(eth+1);
335 /* we only want TCP */
336 if (ip6->ip6_nxt != IPPROTO_TCP) {
337 return -1;
340 /* TCP */
341 tcp = (struct tcphdr *)(ip6+1);
343 /* tell the caller which one we've found */
344 src->ip6.sin6_family = AF_INET6;
345 src->ip6.sin6_port = tcp->th_sport;
346 src->ip6.sin6_addr = ip6->ip6_src;
348 dst->ip6.sin6_family = AF_INET6;
349 dst->ip6.sin6_port = tcp->th_dport;
350 dst->ip6.sin6_addr = ip6->ip6_dst;
352 *ack_seq = tcp->th_ack;
353 *seq = tcp->th_seq;
355 return 0;
358 return -1;
361 bool ctdb_sys_check_iface_exists(const char *iface)
363 /* FIXME FreeBSD: Interface always considered present */
364 return true;
367 int ctdb_get_peer_pid(const int fd, pid_t *peer_pid)
369 /* FIXME FreeBSD: get_peer_pid not implemented */
370 return 1;
373 char *ctdb_get_process_name(pid_t pid)
375 char path[32];
376 char buf[PATH_MAX];
377 char *ptr;
378 int n;
380 snprintf(path, sizeof(path), "/proc/%d/exe", pid);
381 n = readlink(path, buf, sizeof(buf));
382 if (n < 0) {
383 return NULL;
386 /* Remove any extra fields */
387 buf[n] = '\0';
388 ptr = strtok(buf, " ");
389 return strdup(ptr);
390 return NULL;
393 int ctdb_set_process_name(const char *name)
395 /* FIXME FreeBSD: set_process_name not implemented */
396 return -ENOSYS;
399 bool ctdb_get_lock_info(pid_t req_pid, struct ctdb_lock_info *lock_info)
401 /* FIXME FreeBSD: get_lock_info not implemented */
402 return false;
405 bool ctdb_get_blocker_pid(struct ctdb_lock_info *reqlock, pid_t *blocker_pid)
407 /* FIXME FreeBSD: get_blocker_pid not implemented */
408 return false;