ctdb-common: Rename system utility files
[vlendec/samba-autobuild/.git] / ctdb / common / system_freebsd.c
1 /* 
2    ctdb system specific code to manage raw sockets on freebsd
3
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
8
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.
13    
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.
18    
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/>.
21
22
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.
25 */
26
27 #include "replace.h"
28 #include "system/network.h"
29 #include "system/filesys.h"
30 #include "system/wait.h"
31
32 #include "lib/util/debug.h"
33 #include "lib/util/blocking.h"
34
35 #include "protocol/protocol.h"
36
37 #include <net/ethernet.h>
38 #include <netinet/ip6.h>
39 #include <net/if_arp.h>
40 #include <pcap.h>
41
42 #include "common/logging.h"
43 #include "common/system.h"
44 #include "common/system_socket.h"
45
46 #ifndef ETHERTYPE_IP6
47 #define ETHERTYPE_IP6 0x86dd
48 #endif
49
50 /*
51   calculate the tcp checksum for tcp over ipv6
52 */
53 static uint16_t tcp_checksum6(uint16_t *data, size_t n, struct ip6_hdr *ip6)
54 {
55         uint32_t phdr[2];
56         uint32_t sum = 0;
57         uint16_t sum2;
58
59         sum += uint16_checksum((uint16_t *)(void *)&ip6->ip6_src, 16);
60         sum += uint16_checksum((uint16_t *)(void *)&ip6->ip6_dst, 16);
61
62         phdr[0] = htonl(n);
63         phdr[1] = htonl(ip6->ip6_nxt);
64         sum += uint16_checksum((uint16_t *)phdr, 8);
65
66         sum += uint16_checksum(data, n);
67
68         sum = (sum & 0xFFFF) + (sum >> 16);
69         sum = (sum & 0xFFFF) + (sum >> 16);
70         sum2 = htons(sum);
71         sum2 = ~sum2;
72         if (sum2 == 0) {
73                 return 0xFFFF;
74         }
75         return sum2;
76 }
77
78 /*
79   send gratuitous arp reply after we have taken over an ip address
80
81   saddr is the address we are trying to claim
82   iface is the interface name we will be using to claim the address
83  */
84 int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface)
85 {
86         /* FIXME FreeBSD: We don't do gratuitous arp yet */
87         return -1;
88 }
89
90
91 /*
92   simple TCP checksum - assumes data is multiple of 2 bytes long
93  */
94 static uint16_t tcp_checksum(uint16_t *data, size_t n, struct ip *ip)
95 {
96         uint32_t sum = uint16_checksum(data, n);
97         uint16_t sum2;
98         sum += uint16_checksum((uint16_t *)(void *)&ip->ip_src,
99                                sizeof(ip->ip_src));
100         sum += uint16_checksum((uint16_t *)(void *)&ip->ip_dst,
101                                sizeof(ip->ip_dst));
102         sum += ip->ip_p + n;
103         sum = (sum & 0xFFFF) + (sum >> 16);
104         sum = (sum & 0xFFFF) + (sum >> 16);
105         sum2 = htons(sum);
106         sum2 = ~sum2;
107         if (sum2 == 0) {
108                 return 0xFFFF;
109         }
110         return sum2;
111 }
112
113 /*
114   Send tcp segment from the specified IP/port to the specified
115   destination IP/port. 
116
117   This is used to trigger the receiving host into sending its own ACK,
118   which should trigger early detection of TCP reset by the client
119   after IP takeover
120
121   This can also be used to send RST segments (if rst is true) and also
122   if correct seq and ack numbers are provided.
123  */
124 int ctdb_sys_send_tcp(const ctdb_sock_addr *dest, 
125                       const ctdb_sock_addr *src,
126                       uint32_t seq, uint32_t ack, int rst)
127 {
128         int s;
129         int ret;
130         uint32_t one = 1;
131         uint16_t tmpport;
132         ctdb_sock_addr *tmpdest;
133         struct {
134                 struct ip ip;
135                 struct tcphdr tcp;
136         } ip4pkt;
137         struct {
138                 struct ip6_hdr ip6;
139                 struct tcphdr tcp;
140         } ip6pkt;
141         int saved_errno;
142
143         switch (src->ip.sin_family) {
144         case AF_INET:
145                 ZERO_STRUCT(ip4pkt);
146                 ip4pkt.ip.ip_v  = 4;
147                 ip4pkt.ip.ip_hl    = sizeof(ip4pkt.ip)/4;
148                 ip4pkt.ip.ip_len   = htons(sizeof(ip4pkt));
149                 ip4pkt.ip.ip_ttl   = 255;
150                 ip4pkt.ip.ip_p     = IPPROTO_TCP;
151                 ip4pkt.ip.ip_src.s_addr = src->ip.sin_addr.s_addr;
152                 ip4pkt.ip.ip_dst.s_addr = dest->ip.sin_addr.s_addr;
153                 ip4pkt.ip.ip_sum   = 0;
154
155                 ip4pkt.tcp.th_sport = src->ip.sin_port;
156                 ip4pkt.tcp.th_dport = dest->ip.sin_port;
157                 ip4pkt.tcp.th_seq   = seq;
158                 ip4pkt.tcp.th_ack   = ack;
159                 ip4pkt.tcp.th_flags = 0;
160                 ip4pkt.tcp.th_flags |= TH_ACK;
161                 if (rst) {
162                         ip4pkt.tcp.th_flags |= TH_RST;
163                 }
164                 ip4pkt.tcp.th_off   = sizeof(ip4pkt.tcp)/4;
165                 /* this makes it easier to spot in a sniffer */
166                 ip4pkt.tcp.th_win   = htons(1234);
167                 ip4pkt.tcp.th_sum   = tcp_checksum((uint16_t *)&ip4pkt.tcp, sizeof(ip4pkt.tcp), &ip4pkt.ip);
168
169                 /* open a raw socket to send this segment from */
170                 s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
171                 if (s == -1) {
172                         DEBUG(DEBUG_CRIT,(__location__ " failed to open raw socket (%s)\n",
173                                  strerror(errno)));
174                         return -1;
175                 }
176
177                 ret = setsockopt(s, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one));
178                 if (ret != 0) {
179                         DEBUG(DEBUG_CRIT,(__location__ " failed to setup IP headers (%s)\n",
180                                  strerror(errno)));
181                         close(s);
182                         return -1;
183                 }
184
185                 ret = sendto(s, &ip4pkt, sizeof(ip4pkt), 0,
186                              (const struct sockaddr *)&dest->ip,
187                              sizeof(dest->ip));
188                 saved_errno = errno;
189                 close(s);
190                 if (ret != sizeof(ip4pkt)) {
191                         DEBUG(DEBUG_ERR,
192                               ("Failed sendto (%s)\n", strerror(saved_errno)));
193                         return -1;
194                 }
195                 break;
196         case AF_INET6:
197                 ZERO_STRUCT(ip6pkt);
198                 ip6pkt.ip6.ip6_vfc  = 0x60;
199                 ip6pkt.ip6.ip6_plen = htons(20);
200                 ip6pkt.ip6.ip6_nxt  = IPPROTO_TCP;
201                 ip6pkt.ip6.ip6_hlim = 64;
202                 ip6pkt.ip6.ip6_src  = src->ip6.sin6_addr;
203                 ip6pkt.ip6.ip6_dst  = dest->ip6.sin6_addr;
204
205                 ip6pkt.tcp.th_sport = src->ip6.sin6_port;
206                 ip6pkt.tcp.th_dport = dest->ip6.sin6_port;
207                 ip6pkt.tcp.th_seq   = seq;
208                 ip6pkt.tcp.th_ack   = ack;
209                 ip6pkt.tcp.th_flags = 0;
210                 ip6pkt.tcp.th_flags |= TH_ACK;
211                 if (rst) {
212                         ip6pkt.tcp.th_flags |= TH_RST;
213                 }
214                 ip6pkt.tcp.th_off   = sizeof(ip6pkt.tcp)/4;
215                 /* this makes it easier to spot in a sniffer */
216                 ip6pkt.tcp.th_win   = htons(1234);
217                 ip6pkt.tcp.th_sum   = tcp_checksum6((uint16_t *)&ip6pkt.tcp, sizeof(ip6pkt.tcp), &ip6pkt.ip6);
218
219                 s = socket(AF_INET6, SOCK_RAW, IPPROTO_RAW);
220                 if (s == -1) {
221                         DEBUG(DEBUG_CRIT, (__location__ " Failed to open sending socket\n"));
222                         return -1;
223
224                 }
225                 /* sendto() don't like if the port is set and the socket is
226                    in raw mode.
227                 */
228                 tmpdest = discard_const(dest);
229                 tmpport = tmpdest->ip6.sin6_port;
230
231                 tmpdest->ip6.sin6_port = 0;
232                 ret = sendto(s, &ip6pkt, sizeof(ip6pkt), 0,
233                              (const struct sockaddr *)&dest->ip6,
234                              sizeof(dest->ip6));
235                 saved_errno = errno;
236                 tmpdest->ip6.sin6_port = tmpport;
237                 close(s);
238
239                 if (ret != sizeof(ip6pkt)) {
240                         DEBUG(DEBUG_ERR,
241                               ("Failed sendto (%s)\n", strerror(saved_errno)));
242                         return -1;
243                 }
244                 break;
245
246         default:
247                 DEBUG(DEBUG_CRIT,(__location__ " not an ipv4/v6 address\n"));
248                 return -1;
249         }
250
251         return 0;
252 }
253
254 /* 
255    This function is used to open a raw socket to capture from
256  */
257 int ctdb_sys_open_capture_socket(const char *iface, void **private_data)
258 {
259         pcap_t *pt;
260
261         pt=pcap_open_live(iface, 100, 0, 0, NULL);
262         if (pt == NULL) {
263                 DEBUG(DEBUG_CRIT,("Failed to open capture device %s\n", iface));
264                 return -1;
265         }
266         *((pcap_t **)private_data) = pt;
267
268         return pcap_fileno(pt);
269 }
270
271 /* This function is used to close the capture socket
272  */
273 int ctdb_sys_close_capture_socket(void *private_data)
274 {
275         pcap_t *pt = (pcap_t *)private_data;
276         pcap_close(pt);
277         return 0;
278 }
279
280
281 /*
282   called when the raw socket becomes readable
283  */
284 int ctdb_sys_read_tcp_packet(int s, void *private_data, 
285                              ctdb_sock_addr *src, ctdb_sock_addr *dst,
286                              uint32_t *ack_seq, uint32_t *seq,
287                              int *rst, uint16_t *window)
288 {
289         int ret;
290 #define RCVPKTSIZE 100
291         char pkt[RCVPKTSIZE];
292         struct ether_header *eth;
293         struct ip *ip;
294         struct ip6_hdr *ip6;
295         struct tcphdr *tcp;
296
297         ret = recv(s, pkt, RCVPKTSIZE, MSG_TRUNC);
298         if (ret < sizeof(*eth)+sizeof(*ip)) {
299                 return -1;
300         }
301
302         ZERO_STRUCTP(src);
303         ZERO_STRUCTP(dst);
304
305         /* Ethernet */
306         eth = (struct ether_header *)pkt;
307
308         /* we want either IPv4 or IPv6 */
309         if (ntohs(eth->ether_type) == ETHERTYPE_IP) {
310                 /* IP */
311                 ip = (struct ip *)(eth+1);
312
313                 /* We only want IPv4 packets */
314                 if (ip->ip_v != 4) {
315                         return -1;
316                 }
317                 /* Dont look at fragments */
318                 if ((ntohs(ip->ip_off)&0x1fff) != 0) {
319                         return -1;
320                 }
321                 /* we only want TCP */
322                 if (ip->ip_p != IPPROTO_TCP) {
323                         return -1;
324                 }
325
326                 /* make sure its not a short packet */
327                 if (offsetof(struct tcphdr, th_ack) + 4 + 
328                     (ip->ip_hl*4) + sizeof(*eth) > ret) {
329                         return -1;
330                 }
331                 /* TCP */
332                 tcp = (struct tcphdr *)((ip->ip_hl*4) + (char *)ip);
333
334                 /* tell the caller which one we've found */
335                 src->ip.sin_family      = AF_INET;
336                 src->ip.sin_addr.s_addr = ip->ip_src.s_addr;
337                 src->ip.sin_port        = tcp->th_sport;
338                 dst->ip.sin_family      = AF_INET;
339                 dst->ip.sin_addr.s_addr = ip->ip_dst.s_addr;
340                 dst->ip.sin_port        = tcp->th_dport;
341                 *ack_seq                = tcp->th_ack;
342                 *seq                    = tcp->th_seq;
343                 if (window != NULL) {
344                         *window = tcp->th_win;
345                 }
346                 if (rst != NULL) {
347                         *rst = tcp->th_flags & TH_RST;
348                 }
349
350                 return 0;
351         } else if (ntohs(eth->ether_type) == ETHERTYPE_IP6) {
352                 /* IP6 */
353                 ip6 = (struct ip6_hdr *)(eth+1);
354
355                 /* we only want TCP */
356                 if (ip6->ip6_nxt != IPPROTO_TCP) {
357                         return -1;
358                 }
359
360                 /* TCP */
361                 tcp = (struct tcphdr *)(ip6+1);
362
363                 /* tell the caller which one we've found */
364                 src->ip6.sin6_family = AF_INET6;
365                 src->ip6.sin6_port   = tcp->th_sport;
366                 src->ip6.sin6_addr   = ip6->ip6_src;
367
368                 dst->ip6.sin6_family = AF_INET6;
369                 dst->ip6.sin6_port   = tcp->th_dport;
370                 dst->ip6.sin6_addr   = ip6->ip6_dst;
371
372                 *ack_seq             = tcp->th_ack;
373                 *seq                 = tcp->th_seq;
374                 if (window != NULL) {
375                         *window = tcp->th_win;
376                 }
377                 if (rst != NULL) {
378                         *rst = tcp->th_flags & TH_RST;
379                 }
380
381                 return 0;
382         }
383
384         return -1;
385 }
386
387 bool ctdb_sys_check_iface_exists(const char *iface)
388 {
389         /* FIXME FreeBSD: Interface always considered present */
390         return true;
391 }
392
393 int ctdb_get_peer_pid(const int fd, pid_t *peer_pid)
394 {
395         /* FIXME FreeBSD: get_peer_pid not implemented */
396         return 1;
397 }