Merge remote branch 'ddiss/master_pmda_and_client_timeouts'
[samba.git] / ctdb / common / system_aix.c
1 /* 
2    ctdb system specific code to manage raw sockets on aix
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
22 #include "includes.h"
23 #include "system/network.h"
24 #include "system/filesys.h"
25 #include "system/wait.h"
26 #include "../include/ctdb_private.h"
27 #include <netinet/if_ether.h>
28 #include <netinet/ip6.h>
29 #include <net/if_arp.h>
30 #include <sys/ndd_var.h>
31 #include <sys/kinfo.h>
32 #include <pcap.h>
33
34
35
36 #if 0
37 This function is no longer used and its code should be moved into
38 send tcp packet   after that function has been enhanced to do ipv6 as well.
39
40 /* This function is used to open a raw socket to send tickles from
41  */
42 int ctdb_sys_open_sending_socket(void)
43 {
44         int s, ret;
45         uint32_t one = 1;
46
47         s = socket(AF_INET, SOCK_RAW, htons(IPPROTO_RAW));
48         if (s == -1) {
49                 DEBUG(DEBUG_CRIT,(" failed to open raw socket (%s)\n",
50                          strerror(errno)));
51                 return -1;
52         }
53
54         ret = setsockopt(s, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one));
55         if (ret != 0) {
56                 DEBUG(DEBUG_CRIT, (" failed to setup IP headers (%s)\n",
57                          strerror(errno)));
58                 close(s);
59                 return -1;
60         }
61
62         set_nonblocking(s);
63         set_close_on_exec(s);
64
65         return s;
66 }
67 #endif
68
69 /*
70   simple TCP checksum - assumes data is multiple of 2 bytes long
71  */
72 static uint16_t tcp_checksum(uint16_t *data, size_t n, struct ip *ip)
73 {
74         uint32_t sum = uint16_checksum(data, n);
75         uint16_t sum2;
76
77         sum += uint16_checksum((uint16_t *)&ip->ip_src, sizeof(ip->ip_src));
78         sum += uint16_checksum((uint16_t *)&ip->ip_dst, sizeof(ip->ip_dst));
79         sum += ip->ip_p + n;
80         sum = (sum & 0xFFFF) + (sum >> 16);
81         sum = (sum & 0xFFFF) + (sum >> 16);
82         sum2 = htons(sum);
83         sum2 = ~sum2;
84         if (sum2 == 0) {
85                 return 0xFFFF;
86         }
87         return sum2;
88 }
89
90 /*
91   Send tcp segment from the specified IP/port to the specified
92   destination IP/port. 
93
94   This is used to trigger the receiving host into sending its own ACK,
95   which should trigger early detection of TCP reset by the client
96   after IP takeover
97
98   This can also be used to send RST segments (if rst is true) and also
99   if correct seq and ack numbers are provided.
100  */
101 int ctdb_sys_send_tcp(const ctdb_sock_addr *dest,
102                       const ctdb_sock_addr *src,
103                       uint32_t seq, uint32_t ack, int rst)
104 {
105         int s;
106         int ret;
107         uint32_t one = 1;
108         ctdb_sock_addr *tmpdest;
109         
110         struct {
111                 struct ip ip;
112                 struct tcphdr tcp;
113         } ip4pkt;
114
115
116         /* for now, we only handle AF_INET addresses */
117         if (src->ip.sin_family != AF_INET || dest->ip.sin_family != AF_INET) {
118                 DEBUG(DEBUG_CRIT,(__location__ " not an ipv4 address\n"));
119                 return -1;
120         }
121
122
123
124         s = socket(AF_INET, SOCK_RAW, htons(IPPROTO_RAW));
125         if (s == -1) {
126                 DEBUG(DEBUG_CRIT,(" failed to open raw socket (%s)\n",
127                          strerror(errno)));
128                 return -1;
129         }
130
131         ret = setsockopt(s, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one));
132         if (ret != 0) {
133                 DEBUG(DEBUG_CRIT, (" failed to setup IP headers (%s)\n",
134                          strerror(errno)));
135                 close(s);
136                 return -1;
137         }
138
139         set_nonblocking(s);
140         set_close_on_exec(s);
141
142         memset(&ip4pkt, 0, sizeof(ip4pkt));
143         ip4pkt.ip.ip_v     = 4;
144         ip4pkt.ip.ip_hl    = sizeof(ip4pkt.ip)/4;
145         ip4pkt.ip.ip_len   = htons(sizeof(ip4pkt));
146         ip4pkt.ip.ip_ttl   = 255;
147         ip4pkt.ip.ip_p     = IPPROTO_TCP;
148         ip4pkt.ip.ip_src.s_addr   = src->ip.sin_addr.s_addr;
149         ip4pkt.ip.ip_dst.s_addr   = dest->ip.sin_addr.s_addr;
150         ip4pkt.ip.ip_sum   = 0;
151
152         ip4pkt.tcp.th_sport   = src->ip.sin_port;
153         ip4pkt.tcp.th_dport     = dest->ip.sin_port;
154         ip4pkt.tcp.th_seq      = seq;
155         ip4pkt.tcp.th_ack    = ack;
156         ip4pkt.tcp.th_flags  = TH_ACK;
157         if (rst) {
158                 ip4pkt.tcp.th_flags      = TH_RST;
159         }
160         ip4pkt.tcp.th_off    = sizeof(ip4pkt.tcp)/4;
161         ip4pkt.tcp.th_win   = htons(1234);
162         ip4pkt.tcp.th_sum    = tcp_checksum((uint16_t *)&ip4pkt.tcp, sizeof(ip4pkt.tcp), &ip4pkt.ip);
163
164         ret = sendto(s, &ip4pkt, sizeof(ip4pkt), 0, (struct sockaddr *)dest, sizeof(*dest));
165         if (ret != sizeof(ip4pkt)) {
166                 DEBUG(DEBUG_CRIT,(__location__ " failed sendto (%s)\n", strerror(errno)));
167                 return -1;
168         }
169
170         return 0;
171 }
172
173 /* This function is used to open a raw socket to capture from
174  */
175 int ctdb_sys_open_capture_socket(const char *iface, void **private_data)
176 {
177         pcap_t *pt;
178
179         pt=pcap_open_live(iface, 100, 0, 0, NULL);
180         if (pt == NULL) {
181                 DEBUG(DEBUG_CRIT,("Failed to open capture device %s\n", iface));
182                 return -1;
183         }
184         *((pcap_t **)private_data) = pt;
185
186         return pcap_fileno(pt);
187 }
188
189
190 /* This function is used to close the capture socket
191  */
192 int ctdb_sys_close_capture_socket(void *private_data)
193 {
194         pcap_t *pt = (pcap_t *)private_data;
195         pcap_close(pt);
196         return 0;
197 }
198
199
200
201 /*
202   send gratuitous arp reply after we have taken over an ip address
203
204   saddr is the address we are trying to claim
205   iface is the interface name we will be using to claim the address
206  */
207 int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface)
208 {
209         /* We dont do grat arp on aix yet */
210         return 0;
211 }
212
213
214
215 /*
216   get ethernet MAC address on AIX
217  */
218 static int aix_get_mac_addr(const char *device_name, uint8_t mac[6])
219 {
220         size_t ksize;
221         struct kinfo_ndd *ndd;
222         int count, i;
223
224         ksize = getkerninfo(KINFO_NDD, 0, 0, 0);
225         if (ksize == 0) {
226                 errno = ENOSYS;
227                 return -1;
228         }
229
230         ndd = (struct kinfo_ndd *)malloc(ksize);
231         if (ndd == NULL) {
232                 errno = ENOMEM;
233                 return -1;
234         }
235
236         if (getkerninfo(KINFO_NDD, ndd, &ksize, 0) == -1) {
237                 errno = ENOSYS;
238                 return -1;
239         }
240
241         count= ksize/sizeof(struct kinfo_ndd);
242         for (i=0;i<count;i++) {
243                 if ( (ndd[i].ndd_type != NDD_ETHER) 
244                 &&   (ndd[i].ndd_type != NDD_ISO88023) ) {
245                         continue;
246                 }
247                 if (ndd[i].ndd_addrlen != 6) {
248                         continue;
249                 }
250                 if (!(ndd[i].ndd_flags&NDD_UP)) {
251                         continue;
252                 }
253                 if ( strcmp(device_name, ndd[i].ndd_name)
254                 &&   strcmp(device_name, ndd[i].ndd_alias) ) {
255                         continue;
256                 }
257                 memcpy(mac, ndd[i].ndd_addr, 6);
258                 free(ndd);
259                 return 0;
260         }
261         free(ndd);
262         errno = ENOENT;
263         return -1;
264 }
265
266 int ctdb_sys_read_tcp_packet(int s, void *private_data, 
267                         ctdb_sock_addr *src, ctdb_sock_addr *dst,
268                         uint32_t *ack_seq, uint32_t *seq)
269 {
270         int ret;
271         struct ether_header *eth;
272         struct ip *ip;
273         struct ip6_hdr *ip6;
274         struct tcphdr *tcp;
275         struct ctdb_killtcp_connection *conn;
276         struct pcap_pkthdr pkthdr;
277         const u_char *buffer;
278         pcap_t *pt = (pcap_t *)private_data;
279
280         buffer=pcap_next(pt, &pkthdr);
281         if (buffer==NULL) {
282                 return -1;
283         }
284
285         /* Ethernet */
286         eth = (struct ether_header *)buffer;
287
288         /* we want either IPv4 or IPv6 */
289         if (eth->ether_type == htons(ETHERTYPE_IP)) {
290                 /* IP */
291                 ip = (struct ip *)(eth+1);
292
293                 /* We only want IPv4 packets */
294                 if (ip->ip_v != 4) {
295                         return -1;
296                 }
297                 /* Dont look at fragments */
298                 if ((ntohs(ip->ip_off)&0x1fff) != 0) {
299                         return -1;
300                 }
301                 /* we only want TCP */
302                 if (ip->ip_p != IPPROTO_TCP) {
303                         return -1;
304                 }
305
306                 /* make sure its not a short packet */
307                 if (offsetof(struct tcphdr, th_ack) + 4 + 
308                     (ip->ip_hl*4) > ret) {
309                         return -1;
310                 }
311                 /* TCP */
312                 tcp = (struct tcphdr *)((ip->ip_hl*4) + (char *)ip);
313         
314                 /* tell the caller which one we've found */
315                 src->ip.sin_family      = AF_INET;
316                 src->ip.sin_addr.s_addr = ip->ip_src.s_addr;
317                 src->ip.sin_port        = tcp->th_sport;
318                 dst->ip.sin_family      = AF_INET;
319                 dst->ip.sin_addr.s_addr = ip->ip_dst.s_addr;
320                 dst->ip.sin_port        = tcp->th_dport;
321                 *ack_seq                = tcp->th_ack;
322                 *seq                    = tcp->th_seq;
323
324
325                 return 0;
326 #ifndef ETHERTYPE_IP6
327 #define ETHERTYPE_IP6 0x86dd
328 #endif
329         } else if (eth->ether_type == htons(ETHERTYPE_IP6)) {
330                         /* IP6 */
331                 ip6 = (struct ip6_hdr *)(eth+1);
332
333                 /* we only want TCP */
334                 if (ip6->ip6_nxt != IPPROTO_TCP) {
335                         return -1;
336                 }
337
338                 /* TCP */
339                 tcp = (struct tcphdr *)(ip6+1);
340
341                 /* tell the caller which one we've found */
342                 src->ip6.sin6_family = AF_INET6;
343                 src->ip6.sin6_port   = tcp->th_sport;
344                 src->ip6.sin6_addr   = ip6->ip6_src;
345
346                 dst->ip6.sin6_family = AF_INET6;
347                 dst->ip6.sin6_port   = tcp->th_dport;
348                 dst->ip6.sin6_addr   = ip6->ip6_dst;
349
350                 *ack_seq             = tcp->th_ack;
351                 *seq                 = tcp->th_seq;
352
353                 return 0;
354         }
355
356         return -1;
357 }
358
359
360 bool ctdb_sys_check_iface_exists(const char *iface)
361 {
362         return true;
363 }
364