ctdb-common: Move ctdb_get_peer_pid() to system.[ch]
[vlendec/samba-autobuild/.git] / ctdb / common / system_kfreebsd.c
1 /* 
2    ctdb system specific code to manage raw sockets on linux
3
4    Copyright (C) Ronnie Sahlberg  2007
5    Copyright (C) Andrew Tridgell  2007
6    Copyright (C) Marc Dequènes (Duck) 2009
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, see <http://www.gnu.org/licenses/>.
20
21
22   This file is a copy of 'common/system_linux.c' adapted for Hurd^W kFreeBSD
23   needs, and inspired by 'common/system_aix.c' for the pcap usage.
24 */
25
26 #include "replace.h"
27 #include "system/network.h"
28 #include "system/filesys.h"
29 #include "system/wait.h"
30
31 #include "lib/util/debug.h"
32 #include "lib/util/blocking.h"
33
34 #include "protocol/protocol.h"
35
36 #include <net/ethernet.h>
37 #include <netinet/ip6.h>
38 #include <net/if_arp.h>
39 #include <pcap.h>
40
41 #include "common/logging.h"
42 #include "common/system.h"
43 #include "common/system_socket.h"
44
45 #ifndef ETHERTYPE_IP6
46 #define ETHERTYPE_IP6 0x86dd
47 #endif
48
49 /*
50   calculate the tcp checksum for tcp over ipv6
51 */
52 static uint16_t tcp_checksum6(uint16_t *data, size_t n, struct ip6_hdr *ip6)
53 {
54         uint32_t phdr[2];
55         uint32_t sum = 0;
56         uint16_t sum2;
57
58         sum += uint16_checksum((uint16_t *)(void *)&ip6->ip6_src, 16);
59         sum += uint16_checksum((uint16_t *)(void *)&ip6->ip6_dst, 16);
60
61         phdr[0] = htonl(n);
62         phdr[1] = htonl(ip6->ip6_nxt);
63         sum += uint16_checksum((uint16_t *)phdr, 8);
64
65         sum += uint16_checksum(data, n);
66
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;
73         }
74         return sum2;
75 }
76
77 /*
78   send gratuitous arp reply after we have taken over an ip address
79
80   saddr is the address we are trying to claim
81   iface is the interface name we will be using to claim the address
82  */
83 int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface)
84 {
85         /* FIXME kFreeBSD: We don't do gratuitous arp yet */
86         return -1;
87 }
88
89
90 /*
91   simple TCP checksum - assumes data is multiple of 2 bytes long
92  */
93 static uint16_t tcp_checksum(uint16_t *data, size_t n, struct iphdr *ip)
94 {
95         uint32_t sum = uint16_checksum(data, n);
96         uint16_t sum2;
97         sum += uint16_checksum((uint16_t *)(void *)&ip->saddr,
98                                sizeof(ip->saddr));
99         sum += uint16_checksum((uint16_t *)(void *)&ip->daddr,
100                                sizeof(ip->daddr));
101         sum += ip->protocol + 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;
108         }
109         return sum2;
110 }
111
112 /*
113   Send tcp segment from the specified IP/port to the specified
114   destination IP/port. 
115
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
119
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.
122  */
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)
126 {
127         int s;
128         int ret;
129         uint32_t one = 1;
130         uint16_t tmpport;
131         ctdb_sock_addr *tmpdest;
132         struct {
133                 struct iphdr ip;
134                 struct tcphdr tcp;
135         } ip4pkt;
136         struct {
137                 struct ip6_hdr ip6;
138                 struct tcphdr tcp;
139         } ip6pkt;
140         int saved_errno;
141
142         switch (src->ip.sin_family) {
143         case AF_INET:
144                 ZERO_STRUCT(ip4pkt);
145                 ip4pkt.ip.version  = 4;
146                 ip4pkt.ip.ihl      = sizeof(ip4pkt.ip)/4;
147                 ip4pkt.ip.tot_len  = htons(sizeof(ip4pkt));
148                 ip4pkt.ip.ttl      = 255;
149                 ip4pkt.ip.protocol = IPPROTO_TCP;
150                 ip4pkt.ip.saddr    = src->ip.sin_addr.s_addr;
151                 ip4pkt.ip.daddr    = dest->ip.sin_addr.s_addr;
152                 ip4pkt.ip.check    = 0;
153
154                 ip4pkt.tcp.source   = src->ip.sin_port;
155                 ip4pkt.tcp.dest     = dest->ip.sin_port;
156                 ip4pkt.tcp.seq      = seq;
157                 ip4pkt.tcp.ack_seq  = ack;
158                 ip4pkt.tcp.ack      = 1;
159                 if (rst) {
160                         ip4pkt.tcp.rst      = 1;
161                 }
162                 ip4pkt.tcp.doff     = sizeof(ip4pkt.tcp)/4;
163                 /* this makes it easier to spot in a sniffer */
164                 ip4pkt.tcp.window   = htons(1234);
165                 ip4pkt.tcp.check    = tcp_checksum((uint16_t *)&ip4pkt.tcp, sizeof(ip4pkt.tcp), &ip4pkt.ip);
166
167                 /* open a raw socket to send this segment from */
168                 s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
169                 if (s == -1) {
170                         DEBUG(DEBUG_CRIT,(__location__ " failed to open raw socket (%s)\n",
171                                  strerror(errno)));
172                         return -1;
173                 }
174
175                 ret = setsockopt(s, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one));
176                 if (ret != 0) {
177                         DEBUG(DEBUG_CRIT,(__location__ " failed to setup IP headers (%s)\n",
178                                  strerror(errno)));
179                         close(s);
180                         return -1;
181                 }
182
183                 ret = sendto(s, &ip4pkt, sizeof(ip4pkt), 0,
184                              &dest->ip, sizeof(dest->ip));
185                 saved_errno = errno;
186                 close(s);
187                 if (ret != sizeof(ip4pkt)) {
188                         DEBUG(DEBUG_ERR,
189                               ("Failed sendto (%s)\n", strerror(saved_errno)));
190                         return -1;
191                 }
192                 break;
193         case AF_INET6:
194                 ZERO_STRUCT(ip6pkt);
195                 ip6pkt.ip6.ip6_vfc  = 0x60;
196                 ip6pkt.ip6.ip6_plen = htons(20);
197                 ip6pkt.ip6.ip6_nxt  = IPPROTO_TCP;
198                 ip6pkt.ip6.ip6_hlim = 64;
199                 ip6pkt.ip6.ip6_src  = src->ip6.sin6_addr;
200                 ip6pkt.ip6.ip6_dst  = dest->ip6.sin6_addr;
201
202                 ip6pkt.tcp.source   = src->ip6.sin6_port;
203                 ip6pkt.tcp.dest     = dest->ip6.sin6_port;
204                 ip6pkt.tcp.seq      = seq;
205                 ip6pkt.tcp.ack_seq  = ack;
206                 ip6pkt.tcp.ack      = 1;
207                 if (rst) {
208                         ip6pkt.tcp.rst      = 1;
209                 }
210                 ip6pkt.tcp.doff     = sizeof(ip6pkt.tcp)/4;
211                 /* this makes it easier to spot in a sniffer */
212                 ip6pkt.tcp.window   = htons(1234);
213                 ip6pkt.tcp.check    = tcp_checksum6((uint16_t *)&ip6pkt.tcp, sizeof(ip6pkt.tcp), &ip6pkt.ip6);
214
215                 s = socket(AF_INET6, SOCK_RAW, IPPROTO_RAW);
216                 if (s == -1) {
217                         DEBUG(DEBUG_CRIT, (__location__ " Failed to open sending socket\n"));
218                         return -1;
219
220                 }
221                 /* sendto() don't like if the port is set and the socket is
222                    in raw mode.
223                 */
224                 tmpdest = discard_const(dest);
225                 tmpport = tmpdest->ip6.sin6_port;
226
227                 tmpdest->ip6.sin6_port = 0;
228                 ret = sendto(s, &ip6pkt, sizeof(ip6pkt), 0,
229                              &dest->ip6, sizeof(dest->ip6));
230                 saved_errno = errno;
231                 tmpdest->ip6.sin6_port = tmpport;
232                 close(s);
233
234                 if (ret != sizeof(ip6pkt)) {
235                         DEBUG(DEBUG_ERR,
236                               ("Failed sendto (%s)\n", strerror(saved_errno)));
237                         return -1;
238                 }
239                 break;
240
241         default:
242                 DEBUG(DEBUG_CRIT,(__location__ " not an ipv4/v6 address\n"));
243                 return -1;
244         }
245
246         return 0;
247 }
248
249 /* 
250    This function is used to open a raw socket to capture from
251  */
252 int ctdb_sys_open_capture_socket(const char *iface, void **private_data)
253 {
254         pcap_t *pt;
255
256         pt=pcap_open_live(iface, 100, 0, 0, NULL);
257         if (pt == NULL) {
258                 DEBUG(DEBUG_CRIT,("Failed to open capture device %s\n", iface));
259                 return -1;
260         }
261         *((pcap_t **)private_data) = pt;
262
263         return pcap_fileno(pt);
264 }
265
266 /* This function is used to close the capture socket
267  */
268 int ctdb_sys_close_capture_socket(void *private_data)
269 {
270         pcap_t *pt = (pcap_t *)private_data;
271         pcap_close(pt);
272         return 0;
273 }
274
275
276 /*
277   called when the raw socket becomes readable
278  */
279 int ctdb_sys_read_tcp_packet(int s, void *private_data,
280                              ctdb_sock_addr *src, ctdb_sock_addr *dst,
281                              uint32_t *ack_seq, uint32_t *seq,
282                              int *rst, uint16_t *window)
283 {
284         int ret;
285 #define RCVPKTSIZE 100
286         char pkt[RCVPKTSIZE];
287         struct ether_header *eth;
288         struct iphdr *ip;
289         struct ip6_hdr *ip6;
290         struct tcphdr *tcp;
291
292         ret = recv(s, pkt, RCVPKTSIZE, MSG_TRUNC);
293         if (ret < sizeof(*eth)+sizeof(*ip)) {
294                 return -1;
295         }
296
297         ZERO_STRUCTP(src);
298         ZERO_STRUCTP(dst);
299
300         /* Ethernet */
301         eth = (struct ether_header *)pkt;
302
303         /* we want either IPv4 or IPv6 */
304         if (ntohs(eth->ether_type) == ETHERTYPE_IP) {
305                 /* IP */
306                 ip = (struct iphdr *)(eth+1);
307
308                 /* We only want IPv4 packets */
309                 if (ip->version != 4) {
310                         return -1;
311                 }
312                 /* Dont look at fragments */
313                 if ((ntohs(ip->frag_off)&0x1fff) != 0) {
314                         return -1;
315                 }
316                 /* we only want TCP */
317                 if (ip->protocol != IPPROTO_TCP) {
318                         return -1;
319                 }
320
321                 /* make sure its not a short packet */
322                 if (offsetof(struct tcphdr, ack_seq) + 4 + 
323                     (ip->ihl*4) + sizeof(*eth) > ret) {
324                         return -1;
325                 }
326                 /* TCP */
327                 tcp = (struct tcphdr *)((ip->ihl*4) + (char *)ip);
328
329                 /* tell the caller which one we've found */
330                 src->ip.sin_family      = AF_INET;
331                 src->ip.sin_addr.s_addr = ip->saddr;
332                 src->ip.sin_port        = tcp->source;
333                 dst->ip.sin_family      = AF_INET;
334                 dst->ip.sin_addr.s_addr = ip->daddr;
335                 dst->ip.sin_port        = tcp->dest;
336                 *ack_seq                = tcp->ack_seq;
337                 *seq                    = tcp->seq;
338                 if (window != NULL) {
339                         *window = tcp->window;
340                 }
341                 if (rst != NULL) {
342                         *rst = tcp->rst;
343                 }
344
345                 return 0;
346         } else if (ntohs(eth->ether_type) == ETHERTYPE_IP6) {
347                 /* IP6 */
348                 ip6 = (struct ip6_hdr *)(eth+1);
349
350                 /* we only want TCP */
351                 if (ip6->ip6_nxt != IPPROTO_TCP) {
352                         return -1;
353                 }
354
355                 /* TCP */
356                 tcp = (struct tcphdr *)(ip6+1);
357
358                 /* tell the caller which one we've found */
359                 src->ip6.sin6_family = AF_INET6;
360                 src->ip6.sin6_port   = tcp->source;
361                 src->ip6.sin6_addr   = ip6->ip6_src;
362
363                 dst->ip6.sin6_family = AF_INET6;
364                 dst->ip6.sin6_port   = tcp->dest;
365                 dst->ip6.sin6_addr   = ip6->ip6_dst;
366
367                 *ack_seq             = tcp->ack_seq;
368                 *seq                 = tcp->seq;
369                 if (window != NULL) {
370                         *window = tcp->window;
371                 }
372                 if (rst != NULL) {
373                         *rst = tcp->rst;
374                 }
375
376                 return 0;
377         }
378
379         return -1;
380 }