Start implementing support for ipv6.
[ambi/samba-autobuild/.git] / ctdb / common / system_linux.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
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include "system/network.h"
23 #include "system/filesys.h"
24 #include "system/wait.h"
25 #include "../include/ctdb_private.h"
26 #include "lib/events/events.h"
27 #include <netinet/if_ether.h>
28 #include <netinet/ip6.h>
29 #include <net/if_arp.h>
30
31
32
33 /*
34   send gratuitous arp reply after we have taken over an ip address
35
36   saddr is the address we are trying to claim
37   iface is the interface name we will be using to claim the address
38  */
39 int ctdb_sys_send_arp(const struct sockaddr_in *saddr, const char *iface)
40 {
41         int s, ret;
42         struct sockaddr sa;
43         struct ether_header *eh;
44         struct arphdr *ah;
45         struct ifreq if_hwaddr;
46         unsigned char buffer[64]; /*minimum eth frame size */
47         char *ptr;
48
49         ZERO_STRUCT(sa);
50
51         /* for now, we only handle AF_INET addresses */
52         if (saddr->sin_family != AF_INET) {
53                 DEBUG(DEBUG_CRIT,(__location__ " not an ipv4 address (family is %u)\n", saddr->sin_family));
54                 return -1;
55         }
56
57         s = socket(AF_INET, SOCK_PACKET, htons(ETHERTYPE_ARP));
58         if (s == -1){
59                 DEBUG(DEBUG_CRIT,(__location__ " failed to open raw socket\n"));
60                 return -1;
61         }
62
63         /* get the mac address */
64         strcpy(if_hwaddr.ifr_name, iface);
65         ret = ioctl(s, SIOCGIFHWADDR, &if_hwaddr);
66         if ( ret < 0 ) {
67                 close(s);
68                 DEBUG(DEBUG_CRIT,(__location__ " ioctl failed\n"));
69                 return -1;
70         }
71         if (ARPHRD_LOOPBACK == if_hwaddr.ifr_hwaddr.sa_family) {
72                 DEBUG(DEBUG_DEBUG,("Ignoring loopback arp request\n"));
73                 close(s);
74                 return 0;
75         }
76         if (if_hwaddr.ifr_hwaddr.sa_family != AF_LOCAL) {
77                 close(s);
78                 errno = EINVAL;
79                 DEBUG(DEBUG_CRIT,(__location__ " not an ethernet address family (0x%x)\n",
80                          if_hwaddr.ifr_hwaddr.sa_family));
81                 return -1;
82         }
83
84
85         memset(buffer, 0 , 64);
86         eh = (struct ether_header *)buffer;
87         memset(eh->ether_dhost, 0xff, ETH_ALEN);
88         memcpy(eh->ether_shost, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
89         eh->ether_type = htons(ETHERTYPE_ARP);
90
91         ah = (struct arphdr *)&buffer[sizeof(struct ether_header)];
92         ah->ar_hrd = htons(ARPHRD_ETHER);
93         ah->ar_pro = htons(ETH_P_IP);
94         ah->ar_hln = ETH_ALEN;
95         ah->ar_pln = 4;
96
97         /* send a gratious arp */
98         ah->ar_op  = htons(ARPOP_REQUEST);
99         ptr = (char *)&ah[1];
100         memcpy(ptr, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
101         ptr+=ETH_ALEN;
102         memcpy(ptr, &saddr->sin_addr, 4);         
103         ptr+=4;
104         memset(ptr, 0, ETH_ALEN); 
105         ptr+=ETH_ALEN;
106         memcpy(ptr, &saddr->sin_addr, 4);         
107         ptr+=4;
108
109         strncpy(sa.sa_data, iface, sizeof(sa.sa_data));
110         ret = sendto(s, buffer, 64, 0, &sa, sizeof(sa));
111         if (ret < 0 ){
112                 close(s);
113                 DEBUG(DEBUG_CRIT,(__location__ " failed sendto\n"));
114                 return -1;
115         }
116
117         /* send unsolicited arp reply broadcast */
118         ah->ar_op  = htons(ARPOP_REPLY);
119         ptr = (char *)&ah[1];
120         memcpy(ptr, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
121         ptr+=ETH_ALEN;
122         memcpy(ptr, &saddr->sin_addr, 4);         
123         ptr+=4;
124         memcpy(ptr, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
125         ptr+=ETH_ALEN;
126         memcpy(ptr, &saddr->sin_addr, 4);         
127         ptr+=4;
128
129         strncpy(sa.sa_data, iface, sizeof(sa.sa_data));
130         ret = sendto(s, buffer, 64, 0, &sa, sizeof(sa));
131         if (ret < 0 ){
132                 DEBUG(DEBUG_CRIT,(__location__ " failed sendto\n"));
133                 return -1;
134         }
135
136         close(s);
137         return 0;
138 }
139
140
141 /*
142   uint16 checksum for n bytes
143  */
144 static uint32_t uint16_checksum(uint16_t *data, size_t n)
145 {
146         uint32_t sum=0;
147         while (n>=2) {
148                 sum += (uint32_t)ntohs(*data);
149                 data++;
150                 n -= 2;
151         }
152         if (n == 1) {
153                 sum += (uint32_t)ntohs(*(uint8_t *)data);
154         }
155         return sum;
156 }
157
158 /*
159   simple TCP checksum - assumes data is multiple of 2 bytes long
160  */
161 static uint16_t tcp_checksum(uint16_t *data, size_t n, struct iphdr *ip)
162 {
163         uint32_t sum = uint16_checksum(data, n);
164         uint16_t sum2;
165         sum += uint16_checksum((uint16_t *)(void *)&ip->saddr,
166                                sizeof(ip->saddr));
167         sum += uint16_checksum((uint16_t *)(void *)&ip->daddr,
168                                sizeof(ip->daddr));
169         sum += ip->protocol + n;
170         sum = (sum & 0xFFFF) + (sum >> 16);
171         sum = (sum & 0xFFFF) + (sum >> 16);
172         sum2 = htons(sum);
173         sum2 = ~sum2;
174         if (sum2 == 0) {
175                 return 0xFFFF;
176         }
177         return sum2;
178 }
179
180 /*
181   calculate the tcp checksum for tcp over ipv6
182 */
183 static uint16_t tcp_checksum6(uint16_t *data, size_t n, struct ip6_hdr *ip6)
184 {
185         uint32_t sum = uint16_checksum(data, n);
186         uint16_t sum2;
187
188         sum += uint16_checksum((uint16_t *)(void *)&ip6->ip6_src, 16);
189         sum += uint16_checksum((uint16_t *)(void *)&ip6->ip6_dst, 16);
190         sum += ip6->ip6_plen;
191         sum += ip6->ip6_nxt;
192                         
193         sum = (sum & 0xFFFF) + (sum >> 16);
194         sum = (sum & 0xFFFF) + (sum >> 16);
195         sum2 = htons(sum);
196         sum2 = ~sum2;
197         if (sum2 == 0) {
198                 return 0xFFFF;
199         }
200         return sum2;
201 }
202
203 /*
204   Send tcp segment from the specified IP/port to the specified
205   destination IP/port. 
206
207   This is used to trigger the receiving host into sending its own ACK,
208   which should trigger early detection of TCP reset by the client
209   after IP takeover
210
211   This can also be used to send RST segments (if rst is true) and also
212   if correct seq and ack numbers are provided.
213  */
214 int ctdb_sys_send_tcp(const ctdb_sock_addr *dest, 
215                       const ctdb_sock_addr *src,
216                       uint32_t seq, uint32_t ack, int rst)
217 {
218         int s;
219         int ret;
220         uint32_t one = 1;
221         uint16_t tmpport;
222         ctdb_sock_addr *tmpdest;
223         struct {
224                 struct iphdr ip;
225                 struct tcphdr tcp;
226         } ip4pkt;
227         struct {
228                 struct ip6_hdr ip6;
229                 struct tcphdr tcp;
230         } ip6pkt;
231
232         switch (src->ip.sin_family) {
233         case AF_INET:
234                 ZERO_STRUCT(ip4pkt);
235                 ip4pkt.ip.version  = 4;
236                 ip4pkt.ip.ihl      = sizeof(ip4pkt.ip)/4;
237                 ip4pkt.ip.tot_len  = htons(sizeof(ip4pkt));
238                 ip4pkt.ip.ttl      = 255;
239                 ip4pkt.ip.protocol = IPPROTO_TCP;
240                 ip4pkt.ip.saddr    = src->ip.sin_addr.s_addr;
241                 ip4pkt.ip.daddr    = dest->ip.sin_addr.s_addr;
242                 ip4pkt.ip.check    = 0;
243
244                 ip4pkt.tcp.source   = src->ip.sin_port;
245                 ip4pkt.tcp.dest     = dest->ip.sin_port;
246                 ip4pkt.tcp.seq      = seq;
247                 ip4pkt.tcp.ack_seq  = ack;
248                 ip4pkt.tcp.ack      = 1;
249                 if (rst) {
250                         ip4pkt.tcp.rst      = 1;
251                 }
252                 ip4pkt.tcp.doff     = sizeof(ip4pkt.tcp)/4;
253                 /* this makes it easier to spot in a sniffer */
254                 ip4pkt.tcp.window   = htons(1234);
255                 ip4pkt.tcp.check    = tcp_checksum((uint16_t *)&ip4pkt.tcp, sizeof(ip4pkt.tcp), &ip4pkt.ip);
256
257                 /* open a raw socket to send this segment from */
258                 s = socket(AF_INET, SOCK_RAW, htons(IPPROTO_RAW));
259                 if (s == -1) {
260                         DEBUG(DEBUG_CRIT,(__location__ " failed to open raw socket (%s)\n",
261                                  strerror(errno)));
262                         return -1;
263                 }
264
265                 ret = setsockopt(s, SOL_IP, IP_HDRINCL, &one, sizeof(one));
266                 if (ret != 0) {
267                         DEBUG(DEBUG_CRIT,(__location__ " failed to setup IP headers (%s)\n",
268                                  strerror(errno)));
269                         close(s);
270                         return -1;
271                 }
272
273                 set_nonblocking(s);
274                 set_close_on_exec(s);
275
276                 ret = sendto(s, &ip4pkt, sizeof(ip4pkt), 0, &dest->ip, sizeof(dest->ip));
277                 close(s);
278                 if (ret != sizeof(ip4pkt)) {
279                         DEBUG(DEBUG_CRIT,(__location__ " failed sendto (%s)\n", strerror(errno)));
280                         return -1;
281                 }
282                 break;
283         case AF_INET6:
284                 ZERO_STRUCT(ip6pkt);
285                 ip6pkt.ip6.ip6_vfc  = 0x60;
286                 ip6pkt.ip6.ip6_plen = 20;
287                 ip6pkt.ip6.ip6_nxt  = IPPROTO_TCP;
288                 ip6pkt.ip6.ip6_hlim = 64;
289                 ip6pkt.ip6.ip6_src  = src->ip6.sin6_addr;
290                 ip6pkt.ip6.ip6_dst  = dest->ip6.sin6_addr;
291
292                 ip6pkt.tcp.source   = src->ip6.sin6_port;
293                 ip6pkt.tcp.dest     = dest->ip6.sin6_port;
294                 ip6pkt.tcp.seq      = seq;
295                 ip6pkt.tcp.ack_seq  = ack;
296                 ip6pkt.tcp.ack      = 1;
297                 if (rst) {
298                         ip6pkt.tcp.rst      = 1;
299                 }
300                 ip6pkt.tcp.doff     = sizeof(ip6pkt.tcp)/4;
301                 /* this makes it easier to spot in a sniffer */
302                 ip6pkt.tcp.window   = htons(1234);
303                 ip6pkt.tcp.check    = tcp_checksum6((uint16_t *)&ip6pkt.tcp, sizeof(ip6pkt.tcp), &ip6pkt.ip6);
304
305                 s = socket(PF_INET6, SOCK_RAW, IPPROTO_RAW);
306                 if (s == -1) {
307                         DEBUG(DEBUG_CRIT, (__location__ " Failed to open sending socket\n"));
308                         return -1;
309
310                 }
311                 /* sendto() dont like if the port is set and the socket is
312                    in raw mode.
313                 */
314                 tmpdest = discard_const(dest);
315                 tmpport = tmpdest->ip6.sin6_port;
316
317                 tmpdest->ip6.sin6_port = 0;
318                 ret = sendto(s, &ip6pkt, sizeof(ip6pkt), 0, &dest->ip6, sizeof(dest->ip6));
319                 tmpdest->ip6.sin6_port = tmpport;
320                 close(s);
321
322                 if (ret != sizeof(ip6pkt)) {
323                         DEBUG(DEBUG_CRIT,(__location__ " failed sendto (%s)\n", strerror(errno)));
324                         return -1;
325                 }
326                 break;
327
328         default:
329                 DEBUG(DEBUG_CRIT,(__location__ " not an ipv4/v6 address\n"));
330                 return -1;
331         }
332
333         return 0;
334 }
335
336
337 /*
338   see if we currently have an interface with the given IP
339
340   we try to bind to it, and if that fails then we don't have that IP
341   on an interface
342
343   ifname, if non-NULL, will return the name of the interface this ip is tied to
344  */
345 bool ctdb_sys_have_ip(struct sockaddr_in ip)
346 {
347         int s;
348         int ret;
349
350         ip.sin_port = 0;
351         s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
352         if (s == -1) {
353                 return false;
354         }
355         ret = bind(s, (struct sockaddr *)&ip, sizeof(ip));
356
357         close(s);
358         return ret == 0;
359 }
360
361 /* 
362    This function is used to open a raw socket to capture from
363  */
364 int ctdb_sys_open_capture_socket(const char *iface, void **private_data)
365 {
366         int s;
367
368         /* Open a socket to capture all traffic */
369         s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
370         if (s == -1) {
371                 DEBUG(DEBUG_CRIT,(__location__ " failed to open raw socket\n"));
372                 return -1;
373         }
374
375         set_nonblocking(s);
376         set_close_on_exec(s);
377
378         return s;
379 }
380
381 /* 
382    This function is used to do any additional cleanup required when closing
383    a capture socket.
384    Note that the socket itself is closed automatically in the caller.
385  */
386 int ctdb_sys_close_capture_socket(void *private_data)
387 {
388         return 0;
389 }
390
391
392 /*
393   called when the raw socket becomes readable
394  */
395 int ctdb_sys_read_tcp_packet(int s, void *private_data, 
396                         struct sockaddr_in *src, struct sockaddr_in *dst,
397                         uint32_t *ack_seq, uint32_t *seq)
398 {
399         int ret;
400 #define RCVPKTSIZE 100
401         char pkt[RCVPKTSIZE];
402         struct ether_header *eth;
403         struct iphdr *ip;
404         struct tcphdr *tcp;
405
406         ret = recv(s, pkt, RCVPKTSIZE, MSG_TRUNC);
407         if (ret < sizeof(*eth)+sizeof(*ip)) {
408                 return -1;
409         }
410
411         /* Ethernet */
412         eth = (struct ether_header *)pkt;
413
414         /* We only want IP packets */
415         if (ntohs(eth->ether_type) != ETHERTYPE_IP) {
416                 return -1;
417         }
418         
419         /* IP */
420         ip = (struct iphdr *)(eth+1);
421
422         /* We only want IPv4 packets */
423         if (ip->version != 4) {
424                 return -1;
425         }
426         /* Dont look at fragments */
427         if ((ntohs(ip->frag_off)&0x1fff) != 0) {
428                 return -1;
429         }
430         /* we only want TCP */
431         if (ip->protocol != IPPROTO_TCP) {
432                 return -1;
433         }
434
435         /* make sure its not a short packet */
436         if (offsetof(struct tcphdr, ack_seq) + 4 + 
437             (ip->ihl*4) + sizeof(*eth) > ret) {
438                 return -1;
439         }
440
441         /* TCP */
442         tcp = (struct tcphdr *)((ip->ihl*4) + (char *)ip);
443
444         /* tell the caller which one we've found */
445         src->sin_addr.s_addr = ip->saddr;
446         src->sin_port        = tcp->source;
447         dst->sin_addr.s_addr = ip->daddr;
448         dst->sin_port        = tcp->dest;
449         *ack_seq             = tcp->ack_seq;
450         *seq                 = tcp->seq;
451
452         return 0;
453 }
454
455