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/>.
23 #include "system/network.h"
24 #include "system/filesys.h"
25 #include "system/wait.h"
27 #include "lib/util/debug.h"
29 #include "protocol/protocol.h"
31 #include <netinet/if_ether.h>
32 #include <netinet/ip6.h>
33 #include <net/if_arp.h>
34 #include <sys/ndd_var.h>
35 #include <sys/kinfo.h>
38 #include "common/logging.h"
39 #include "common/system.h"
43 This function is no longer used and its code should be moved into
44 send tcp packet after that function has been enhanced to do ipv6 as well.
46 /* This function is used to open a raw socket to send tickles from
48 int ctdb_sys_open_sending_socket(void)
53 s = socket(AF_INET, SOCK_RAW, htons(IPPROTO_RAW));
55 DEBUG(DEBUG_CRIT,(" failed to open raw socket (%s)\n",
60 ret = setsockopt(s, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one));
62 DEBUG(DEBUG_CRIT, (" failed to setup IP headers (%s)\n",
76 simple TCP checksum - assumes data is multiple of 2 bytes long
78 static uint16_t tcp_checksum(uint16_t *data, size_t n, struct ip *ip)
80 uint32_t sum = uint16_checksum(data, n);
83 sum += uint16_checksum((uint16_t *)&ip->ip_src, sizeof(ip->ip_src));
84 sum += uint16_checksum((uint16_t *)&ip->ip_dst, sizeof(ip->ip_dst));
86 sum = (sum & 0xFFFF) + (sum >> 16);
87 sum = (sum & 0xFFFF) + (sum >> 16);
97 Send tcp segment from the specified IP/port to the specified
100 This is used to trigger the receiving host into sending its own ACK,
101 which should trigger early detection of TCP reset by the client
104 This can also be used to send RST segments (if rst is true) and also
105 if correct seq and ack numbers are provided.
107 int ctdb_sys_send_tcp(const ctdb_sock_addr *dest,
108 const ctdb_sock_addr *src,
109 uint32_t seq, uint32_t ack, int rst)
114 ctdb_sock_addr *tmpdest;
122 /* for now, we only handle AF_INET addresses */
123 if (src->ip.sin_family != AF_INET || dest->ip.sin_family != AF_INET) {
124 DEBUG(DEBUG_CRIT,(__location__ " not an ipv4 address\n"));
130 s = socket(AF_INET, SOCK_RAW, htons(IPPROTO_RAW));
132 DEBUG(DEBUG_CRIT,(" failed to open raw socket (%s)\n",
137 ret = setsockopt(s, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one));
139 DEBUG(DEBUG_CRIT, (" failed to setup IP headers (%s)\n",
146 set_close_on_exec(s);
148 memset(&ip4pkt, 0, sizeof(ip4pkt));
150 ip4pkt.ip.ip_hl = sizeof(ip4pkt.ip)/4;
151 ip4pkt.ip.ip_len = htons(sizeof(ip4pkt));
152 ip4pkt.ip.ip_ttl = 255;
153 ip4pkt.ip.ip_p = IPPROTO_TCP;
154 ip4pkt.ip.ip_src.s_addr = src->ip.sin_addr.s_addr;
155 ip4pkt.ip.ip_dst.s_addr = dest->ip.sin_addr.s_addr;
156 ip4pkt.ip.ip_sum = 0;
158 ip4pkt.tcp.th_sport = src->ip.sin_port;
159 ip4pkt.tcp.th_dport = dest->ip.sin_port;
160 ip4pkt.tcp.th_seq = seq;
161 ip4pkt.tcp.th_ack = ack;
162 ip4pkt.tcp.th_flags = TH_ACK;
164 ip4pkt.tcp.th_flags = TH_RST;
166 ip4pkt.tcp.th_off = sizeof(ip4pkt.tcp)/4;
167 ip4pkt.tcp.th_win = htons(1234);
168 ip4pkt.tcp.th_sum = tcp_checksum((uint16_t *)&ip4pkt.tcp, sizeof(ip4pkt.tcp), &ip4pkt.ip);
170 ret = sendto(s, &ip4pkt, sizeof(ip4pkt), 0, (struct sockaddr *)dest, sizeof(*dest));
171 if (ret != sizeof(ip4pkt)) {
172 DEBUG(DEBUG_CRIT,(__location__ " failed sendto (%s)\n", strerror(errno)));
179 /* This function is used to open a raw socket to capture from
181 int ctdb_sys_open_capture_socket(const char *iface, void **private_data)
185 pt=pcap_open_live(iface, 100, 0, 0, NULL);
187 DEBUG(DEBUG_CRIT,("Failed to open capture device %s\n", iface));
190 *((pcap_t **)private_data) = pt;
192 return pcap_fileno(pt);
196 /* This function is used to close the capture socket
198 int ctdb_sys_close_capture_socket(void *private_data)
200 pcap_t *pt = (pcap_t *)private_data;
208 send gratuitous arp reply after we have taken over an ip address
210 saddr is the address we are trying to claim
211 iface is the interface name we will be using to claim the address
213 int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface)
215 /* FIXME AIX: We don't do gratuitous arp yet */
222 get ethernet MAC address on AIX
224 static int aix_get_mac_addr(const char *device_name, uint8_t mac[6])
227 struct kinfo_ndd *ndd;
230 ksize = getkerninfo(KINFO_NDD, 0, 0, 0);
236 ndd = (struct kinfo_ndd *)malloc(ksize);
242 if (getkerninfo(KINFO_NDD, ndd, &ksize, 0) == -1) {
247 count= ksize/sizeof(struct kinfo_ndd);
248 for (i=0;i<count;i++) {
249 if ( (ndd[i].ndd_type != NDD_ETHER)
250 && (ndd[i].ndd_type != NDD_ISO88023) ) {
253 if (ndd[i].ndd_addrlen != 6) {
256 if (!(ndd[i].ndd_flags&NDD_UP)) {
259 if ( strcmp(device_name, ndd[i].ndd_name)
260 && strcmp(device_name, ndd[i].ndd_alias) ) {
263 memcpy(mac, ndd[i].ndd_addr, 6);
272 int ctdb_sys_read_tcp_packet(int s, void *private_data,
273 ctdb_sock_addr *src, ctdb_sock_addr *dst,
274 uint32_t *ack_seq, uint32_t *seq)
277 struct ether_header *eth;
281 struct ctdb_killtcp_connection *conn;
282 struct pcap_pkthdr pkthdr;
283 const u_char *buffer;
284 pcap_t *pt = (pcap_t *)private_data;
286 buffer=pcap_next(pt, &pkthdr);
292 eth = (struct ether_header *)buffer;
294 /* we want either IPv4 or IPv6 */
295 if (eth->ether_type == htons(ETHERTYPE_IP)) {
297 ip = (struct ip *)(eth+1);
299 /* We only want IPv4 packets */
303 /* Dont look at fragments */
304 if ((ntohs(ip->ip_off)&0x1fff) != 0) {
307 /* we only want TCP */
308 if (ip->ip_p != IPPROTO_TCP) {
312 /* make sure its not a short packet */
313 if (offsetof(struct tcphdr, th_ack) + 4 +
314 (ip->ip_hl*4) > ret) {
318 tcp = (struct tcphdr *)((ip->ip_hl*4) + (char *)ip);
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;
332 #ifndef ETHERTYPE_IP6
333 #define ETHERTYPE_IP6 0x86dd
335 } else if (eth->ether_type == htons(ETHERTYPE_IP6)) {
337 ip6 = (struct ip6_hdr *)(eth+1);
339 /* we only want TCP */
340 if (ip6->ip6_nxt != IPPROTO_TCP) {
345 tcp = (struct tcphdr *)(ip6+1);
347 /* tell the caller which one we've found */
348 src->ip6.sin6_family = AF_INET6;
349 src->ip6.sin6_port = tcp->th_sport;
350 src->ip6.sin6_addr = ip6->ip6_src;
352 dst->ip6.sin6_family = AF_INET6;
353 dst->ip6.sin6_port = tcp->th_dport;
354 dst->ip6.sin6_addr = ip6->ip6_dst;
356 *ack_seq = tcp->th_ack;
366 bool ctdb_sys_check_iface_exists(const char *iface)
368 /* FIXME AIX: Interface always considered present */
372 int ctdb_get_peer_pid(const int fd, pid_t *peer_pid)
374 struct peercred_struct cr;
375 socklen_t crl = sizeof(struct peercred_struct);
377 if ((ret = getsockopt(fd, SOL_SOCKET, SO_PEERID, &cr, &crl) == 0)) {