system: Remove unused system specific calls
[ctdb.git] / 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 "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>
36
37
38 #ifndef ETHERTYPE_IP6
39 #define ETHERTYPE_IP6 0x86dd
40 #endif
41
42 /*
43   calculate the tcp checksum for tcp over ipv6
44 */
45 static uint16_t tcp_checksum6(uint16_t *data, size_t n, struct ip6_hdr *ip6)
46 {
47         uint32_t phdr[2];
48         uint32_t sum = 0;
49         uint16_t sum2;
50
51         sum += uint16_checksum((uint16_t *)(void *)&ip6->ip6_src, 16);
52         sum += uint16_checksum((uint16_t *)(void *)&ip6->ip6_dst, 16);
53
54         phdr[0] = htonl(n);
55         phdr[1] = htonl(ip6->ip6_nxt);
56         sum += uint16_checksum((uint16_t *)phdr, 8);
57
58         sum += uint16_checksum(data, n);
59
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;
66         }
67         return sum2;
68 }
69
70 /*
71   send gratuitous arp reply after we have taken over an ip address
72
73   saddr is the address we are trying to claim
74   iface is the interface name we will be using to claim the address
75  */
76 int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface)
77 {
78         /* FIXME FreeBSD: We dont do gratuitous arp yet */
79         return -1;
80 }
81
82
83 /*
84   simple TCP checksum - assumes data is multiple of 2 bytes long
85  */
86 static uint16_t tcp_checksum(uint16_t *data, size_t n, struct ip *ip)
87 {
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;
101         }
102         return sum2;
103 }
104
105 /*
106   Send tcp segment from the specified IP/port to the specified
107   destination IP/port. 
108
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
112
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.
115  */
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)
119 {
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;
133
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;
145
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;
154                 }
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);
159
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;
166                 }
167
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;
174                 }
175
176                 set_nonblocking(s);
177                 set_close_on_exec(s);
178
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;
186                 }
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;
196
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;
205                 }
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);
210
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;
215
216                 }
217                 /* sendto() dont like if the port is set and the socket is
218                    in raw mode.
219                 */
220                 tmpdest = discard_const(dest);
221                 tmpport = tmpdest->ip6.sin6_port;
222
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);
229
230                 if (ret != sizeof(ip6pkt)) {
231                         DEBUG(DEBUG_CRIT,(__location__ " failed sendto (%s)\n", strerror(errno)));
232                         return -1;
233                 }
234                 break;
235
236         default:
237                 DEBUG(DEBUG_CRIT,(__location__ " not an ipv4/v6 address\n"));
238                 return -1;
239         }
240
241         return 0;
242 }
243
244 /* 
245    This function is used to open a raw socket to capture from
246  */
247 int ctdb_sys_open_capture_socket(const char *iface, void **private_data)
248 {
249         pcap_t *pt;
250
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;
255         }
256         *((pcap_t **)private_data) = pt;
257
258         return pcap_fileno(pt);
259 }
260
261 /* This function is used to close the capture socket
262  */
263 int ctdb_sys_close_capture_socket(void *private_data)
264 {
265         pcap_t *pt = (pcap_t *)private_data;
266         pcap_close(pt);
267         return 0;
268 }
269
270
271 /*
272   called when the raw socket becomes readable
273  */
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)
277 {
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;
285
286         ret = recv(s, pkt, RCVPKTSIZE, MSG_TRUNC);
287         if (ret < sizeof(*eth)+sizeof(*ip)) {
288                 return -1;
289         }
290
291         /* Ethernet */
292         eth = (struct ether_header *)pkt;
293
294         /* we want either IPv4 or IPv6 */
295         if (ntohs(eth->ether_type) == ETHERTYPE_IP) {
296                 /* IP */
297                 ip = (struct ip *)(eth+1);
298
299                 /* We only want IPv4 packets */
300                 if (ip->ip_v != 4) {
301                         return -1;
302                 }
303                 /* Dont look at fragments */
304                 if ((ntohs(ip->ip_off)&0x1fff) != 0) {
305                         return -1;
306                 }
307                 /* we only want TCP */
308                 if (ip->ip_p != IPPROTO_TCP) {
309                         return -1;
310                 }
311
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;
316                 }
317                 /* TCP */
318                 tcp = (struct tcphdr *)((ip->ip_hl*4) + (char *)ip);
319
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;
329
330                 return 0;
331         } else if (ntohs(eth->ether_type) == ETHERTYPE_IP6) {
332                 /* IP6 */
333                 ip6 = (struct ip6_hdr *)(eth+1);
334
335                 /* we only want TCP */
336                 if (ip6->ip6_nxt != IPPROTO_TCP) {
337                         return -1;
338                 }
339
340                 /* TCP */
341                 tcp = (struct tcphdr *)(ip6+1);
342
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;
347
348                 dst->ip6.sin6_family = AF_INET6;
349                 dst->ip6.sin6_port   = tcp->th_dport;
350                 dst->ip6.sin6_addr   = ip6->ip6_dst;
351
352                 *ack_seq             = tcp->th_ack;
353                 *seq                 = tcp->th_seq;
354
355                 return 0;
356         }
357
358         return -1;
359 }
360
361 bool ctdb_sys_check_iface_exists(const char *iface)
362 {
363         /* FIXME FreeBSD: Interface always considered present */
364         return true;
365 }
366
367 int ctdb_get_peer_pid(const int fd, pid_t *peer_pid)
368 {
369         /* FIXME FreeBSD: get_peer_pid not implemented */
370         return 1;
371 }
372
373 int ctdb_set_process_name(const char *name)
374 {
375         /* FIXME FreeBSD: set_process_name not implemented */
376         return -ENOSYS;
377 }