winbindd_cm: Pass cm_open_connection the need_rw_dc flag
[Samba.git] / ctdb / common / system_aix.c
blobe44d1d6a031e94b90168fabf6fedc185c42fe302
1 /*
2 ctdb system specific code to manage raw sockets on aix
4 Copyright (C) Ronnie Sahlberg 2007
5 Copyright (C) Andrew Tridgell 2007
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.
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.
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/>.
22 #include "replace.h"
23 #include "system/network.h"
24 #include "system/filesys.h"
25 #include "system/wait.h"
27 #include "lib/util/debug.h"
28 #include "lib/util/blocking.h"
30 #include "protocol/protocol.h"
32 #include <netinet/if_ether.h>
33 #include <netinet/ip6.h>
34 #include <net/if_arp.h>
35 #include <sys/ndd_var.h>
36 #include <sys/kinfo.h>
37 #include <pcap.h>
39 #include "common/logging.h"
40 #include "common/system.h"
43 #if 0
44 This function is no longer used and its code should be moved into
45 send tcp packet after that function has been enhanced to do ipv6 as well.
47 /* This function is used to open a raw socket to send tickles from
49 int ctdb_sys_open_sending_socket(void)
51 int s, ret;
52 uint32_t one = 1;
54 s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
55 if (s == -1) {
56 DEBUG(DEBUG_CRIT,(" failed to open raw socket (%s)\n",
57 strerror(errno)));
58 return -1;
61 ret = setsockopt(s, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one));
62 if (ret != 0) {
63 DEBUG(DEBUG_CRIT, (" failed to setup IP headers (%s)\n",
64 strerror(errno)));
65 close(s);
66 return -1;
69 set_blocking(s, false);
70 set_close_on_exec(s);
72 return s;
74 #endif
77 simple TCP checksum - assumes data is multiple of 2 bytes long
79 static uint16_t tcp_checksum(uint16_t *data, size_t n, struct ip *ip)
81 uint32_t sum = uint16_checksum(data, n);
82 uint16_t sum2;
84 sum += uint16_checksum((uint16_t *)&ip->ip_src, sizeof(ip->ip_src));
85 sum += uint16_checksum((uint16_t *)&ip->ip_dst, sizeof(ip->ip_dst));
86 sum += ip->ip_p + n;
87 sum = (sum & 0xFFFF) + (sum >> 16);
88 sum = (sum & 0xFFFF) + (sum >> 16);
89 sum2 = htons(sum);
90 sum2 = ~sum2;
91 if (sum2 == 0) {
92 return 0xFFFF;
94 return sum2;
98 Send tcp segment from the specified IP/port to the specified
99 destination IP/port.
101 This is used to trigger the receiving host into sending its own ACK,
102 which should trigger early detection of TCP reset by the client
103 after IP takeover
105 This can also be used to send RST segments (if rst is true) and also
106 if correct seq and ack numbers are provided.
108 int ctdb_sys_send_tcp(const ctdb_sock_addr *dest,
109 const ctdb_sock_addr *src,
110 uint32_t seq, uint32_t ack, int rst)
112 int s;
113 int ret;
114 uint32_t one = 1;
115 ctdb_sock_addr *tmpdest;
117 struct {
118 struct ip ip;
119 struct tcphdr tcp;
120 } ip4pkt;
121 int saved_errno;
123 /* for now, we only handle AF_INET addresses */
124 if (src->ip.sin_family != AF_INET || dest->ip.sin_family != AF_INET) {
125 DEBUG(DEBUG_CRIT,(__location__ " not an ipv4 address\n"));
126 return -1;
131 s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
132 if (s == -1) {
133 DEBUG(DEBUG_CRIT,(" failed to open raw socket (%s)\n",
134 strerror(errno)));
135 return -1;
138 ret = setsockopt(s, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one));
139 if (ret != 0) {
140 DEBUG(DEBUG_CRIT, (" failed to setup IP headers (%s)\n",
141 strerror(errno)));
142 close(s);
143 return -1;
146 memset(&ip4pkt, 0, sizeof(ip4pkt));
147 ip4pkt.ip.ip_v = 4;
148 ip4pkt.ip.ip_hl = sizeof(ip4pkt.ip)/4;
149 ip4pkt.ip.ip_len = htons(sizeof(ip4pkt));
150 ip4pkt.ip.ip_ttl = 255;
151 ip4pkt.ip.ip_p = IPPROTO_TCP;
152 ip4pkt.ip.ip_src.s_addr = src->ip.sin_addr.s_addr;
153 ip4pkt.ip.ip_dst.s_addr = dest->ip.sin_addr.s_addr;
154 ip4pkt.ip.ip_sum = 0;
156 ip4pkt.tcp.th_sport = src->ip.sin_port;
157 ip4pkt.tcp.th_dport = dest->ip.sin_port;
158 ip4pkt.tcp.th_seq = seq;
159 ip4pkt.tcp.th_ack = ack;
160 ip4pkt.tcp.th_flags = TH_ACK;
161 if (rst) {
162 ip4pkt.tcp.th_flags = TH_RST;
164 ip4pkt.tcp.th_off = sizeof(ip4pkt.tcp)/4;
165 ip4pkt.tcp.th_win = htons(1234);
166 ip4pkt.tcp.th_sum = tcp_checksum((uint16_t *)&ip4pkt.tcp, sizeof(ip4pkt.tcp), &ip4pkt.ip);
168 ret = sendto(s, &ip4pkt, sizeof(ip4pkt), 0,
169 (struct sockaddr *)dest, sizeof(*dest));
170 saved_errno = errno;
171 close(s);
172 if (ret != sizeof(ip4pkt)) {
173 DEBUG(DEBUG_ERR,
174 ("Failed sendto (%s)\n", strerror(saved_errno)));
175 return -1;
178 return 0;
181 /* This function is used to open a raw socket to capture from
183 int ctdb_sys_open_capture_socket(const char *iface, void **private_data)
185 pcap_t *pt;
187 pt=pcap_open_live(iface, 100, 0, 0, NULL);
188 if (pt == NULL) {
189 DEBUG(DEBUG_CRIT,("Failed to open capture device %s\n", iface));
190 return -1;
192 *((pcap_t **)private_data) = pt;
194 return pcap_fileno(pt);
198 /* This function is used to close the capture socket
200 int ctdb_sys_close_capture_socket(void *private_data)
202 pcap_t *pt = (pcap_t *)private_data;
203 pcap_close(pt);
204 return 0;
210 send gratuitous arp reply after we have taken over an ip address
212 saddr is the address we are trying to claim
213 iface is the interface name we will be using to claim the address
215 int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface)
217 /* FIXME AIX: We don't do gratuitous arp yet */
218 return -1;
224 get ethernet MAC address on AIX
226 static int aix_get_mac_addr(const char *device_name, uint8_t mac[6])
228 size_t ksize;
229 struct kinfo_ndd *ndd;
230 int count, i;
232 ksize = getkerninfo(KINFO_NDD, 0, 0, 0);
233 if (ksize == 0) {
234 errno = ENOSYS;
235 return -1;
238 ndd = (struct kinfo_ndd *)malloc(ksize);
239 if (ndd == NULL) {
240 errno = ENOMEM;
241 return -1;
244 if (getkerninfo(KINFO_NDD, ndd, &ksize, 0) == -1) {
245 errno = ENOSYS;
246 return -1;
249 count= ksize/sizeof(struct kinfo_ndd);
250 for (i=0;i<count;i++) {
251 if ( (ndd[i].ndd_type != NDD_ETHER)
252 && (ndd[i].ndd_type != NDD_ISO88023) ) {
253 continue;
255 if (ndd[i].ndd_addrlen != 6) {
256 continue;
258 if (!(ndd[i].ndd_flags&NDD_UP)) {
259 continue;
261 if ( strcmp(device_name, ndd[i].ndd_name)
262 && strcmp(device_name, ndd[i].ndd_alias) ) {
263 continue;
265 memcpy(mac, ndd[i].ndd_addr, 6);
266 free(ndd);
267 return 0;
269 free(ndd);
270 errno = ENOENT;
271 return -1;
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 int *rst, uint16_t *window)
279 int ret;
280 struct ether_header *eth;
281 struct ip *ip;
282 struct ip6_hdr *ip6;
283 struct tcphdr *tcp;
284 struct ctdb_killtcp_connection *conn;
285 struct pcap_pkthdr pkthdr;
286 const u_char *buffer;
287 pcap_t *pt = (pcap_t *)private_data;
289 buffer=pcap_next(pt, &pkthdr);
290 if (buffer==NULL) {
291 return -1;
294 /* Ethernet */
295 eth = (struct ether_header *)buffer;
297 /* we want either IPv4 or IPv6 */
298 if (eth->ether_type == htons(ETHERTYPE_IP)) {
299 /* IP */
300 ip = (struct ip *)(eth+1);
302 /* We only want IPv4 packets */
303 if (ip->ip_v != 4) {
304 return -1;
306 /* Dont look at fragments */
307 if ((ntohs(ip->ip_off)&0x1fff) != 0) {
308 return -1;
310 /* we only want TCP */
311 if (ip->ip_p != IPPROTO_TCP) {
312 return -1;
315 /* make sure its not a short packet */
316 if (offsetof(struct tcphdr, th_ack) + 4 +
317 (ip->ip_hl*4) > ret) {
318 return -1;
320 /* TCP */
321 tcp = (struct tcphdr *)((ip->ip_hl*4) + (char *)ip);
323 /* tell the caller which one we've found */
324 src->ip.sin_family = AF_INET;
325 src->ip.sin_addr.s_addr = ip->ip_src.s_addr;
326 src->ip.sin_port = tcp->th_sport;
327 dst->ip.sin_family = AF_INET;
328 dst->ip.sin_addr.s_addr = ip->ip_dst.s_addr;
329 dst->ip.sin_port = tcp->th_dport;
330 *ack_seq = tcp->th_ack;
331 *seq = tcp->th_seq;
332 if (window != NULL) {
333 *window = tcp->th_win;
335 if (rst != NULL) {
336 *rst = tcp->th_flags & TH_RST;
339 return 0;
340 #ifndef ETHERTYPE_IP6
341 #define ETHERTYPE_IP6 0x86dd
342 #endif
343 } else if (eth->ether_type == htons(ETHERTYPE_IP6)) {
344 /* IP6 */
345 ip6 = (struct ip6_hdr *)(eth+1);
347 /* we only want TCP */
348 if (ip6->ip6_nxt != IPPROTO_TCP) {
349 return -1;
352 /* TCP */
353 tcp = (struct tcphdr *)(ip6+1);
355 /* tell the caller which one we've found */
356 src->ip6.sin6_family = AF_INET6;
357 src->ip6.sin6_port = tcp->th_sport;
358 src->ip6.sin6_addr = ip6->ip6_src;
360 dst->ip6.sin6_family = AF_INET6;
361 dst->ip6.sin6_port = tcp->th_dport;
362 dst->ip6.sin6_addr = ip6->ip6_dst;
364 *ack_seq = tcp->th_ack;
365 *seq = tcp->th_seq;
366 if (window != NULL) {
367 *window = tcp->th_win;
369 if (rst != NULL) {
370 *rst = tcp->th_flags & TH_RST;
373 return 0;
376 return -1;
380 bool ctdb_sys_check_iface_exists(const char *iface)
382 /* FIXME AIX: Interface always considered present */
383 return true;
386 int ctdb_get_peer_pid(const int fd, pid_t *peer_pid)
388 struct peercred_struct cr;
389 socklen_t crl = sizeof(struct peercred_struct);
390 int ret;
391 if ((ret = getsockopt(fd, SOL_SOCKET, SO_PEERID, &cr, &crl)) == 0) {
392 *peer_pid = cr.pid;
394 return ret;