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"
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>
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.
40 /* This function is used to open a raw socket to send tickles from
42 int ctdb_sys_open_sending_socket(void)
47 s = socket(AF_INET, SOCK_RAW, htons(IPPROTO_RAW));
49 DEBUG(DEBUG_CRIT,(" failed to open raw socket (%s)\n",
54 ret = setsockopt(s, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one));
56 DEBUG(DEBUG_CRIT, (" failed to setup IP headers (%s)\n",
70 uint16 checksum for n bytes
72 static uint32_t uint16_checksum(uint16_t *data, size_t n)
76 sum += (uint32_t)ntohs(*data);
81 sum += (uint32_t)ntohs(*(uint8_t *)data);
87 simple TCP checksum - assumes data is multiple of 2 bytes long
89 static uint16_t tcp_checksum(uint16_t *data, size_t n, struct ip *ip)
91 uint32_t sum = uint16_checksum(data, n);
94 sum += uint16_checksum((uint16_t *)&ip->ip_src, sizeof(ip->ip_src));
95 sum += uint16_checksum((uint16_t *)&ip->ip_dst, sizeof(ip->ip_dst));
97 sum = (sum & 0xFFFF) + (sum >> 16);
98 sum = (sum & 0xFFFF) + (sum >> 16);
108 Send tcp segment from the specified IP/port to the specified
111 This is used to trigger the receiving host into sending its own ACK,
112 which should trigger early detection of TCP reset by the client
115 This can also be used to send RST segments (if rst is true) and also
116 if correct seq and ack numbers are provided.
118 int ctdb_sys_send_tcp(const ctdb_sock_addr *dest,
119 const ctdb_sock_addr *src,
120 uint32_t seq, uint32_t ack, int rst)
125 ctdb_sock_addr *tmpdest;
133 /* for now, we only handle AF_INET addresses */
134 if (src->ip.sin_family != AF_INET || dest->ip.sin_family != AF_INET) {
135 DEBUG(DEBUG_CRIT,(__location__ " not an ipv4 address\n"));
141 s = socket(AF_INET, SOCK_RAW, htons(IPPROTO_RAW));
143 DEBUG(DEBUG_CRIT,(" failed to open raw socket (%s)\n",
148 ret = setsockopt(s, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one));
150 DEBUG(DEBUG_CRIT, (" failed to setup IP headers (%s)\n",
157 set_close_on_exec(s);
159 memset(&ip4pkt, 0, sizeof(ip4pkt));
161 ip4pkt.ip.ip_hl = sizeof(ip4pkt.ip)/4;
162 ip4pkt.ip.ip_len = htons(sizeof(ip4pkt));
163 ip4pkt.ip.ip_ttl = 255;
164 ip4pkt.ip.ip_p = IPPROTO_TCP;
165 ip4pkt.ip.ip_src.s_addr = src->ip.sin_addr.s_addr;
166 ip4pkt.ip.ip_dst.s_addr = dest->ip.sin_addr.s_addr;
167 ip4pkt.ip.ip_sum = 0;
169 ip4pkt.tcp.th_sport = src->ip.sin_port;
170 ip4pkt.tcp.th_dport = dest->ip.sin_port;
171 ip4pkt.tcp.th_seq = seq;
172 ip4pkt.tcp.th_ack = ack;
173 ip4pkt.tcp.th_flags = TH_ACK;
175 ip4pkt.tcp.th_flags = TH_RST;
177 ip4pkt.tcp.th_off = sizeof(ip4pkt.tcp)/4;
178 ip4pkt.tcp.th_win = htons(1234);
179 ip4pkt.tcp.th_sum = tcp_checksum((uint16_t *)&ip4pkt.tcp, sizeof(ip4pkt.tcp), &ip4pkt.ip);
181 ret = sendto(s, &ip4pkt, sizeof(ip4pkt), 0, (struct sockaddr *)dest, sizeof(*dest));
182 if (ret != sizeof(ip4pkt)) {
183 DEBUG(DEBUG_CRIT,(__location__ " failed sendto (%s)\n", strerror(errno)));
192 see if we currently have an interface with the given IP
194 we try to bind to it, and if that fails then we don't have that IP
197 bool ctdb_sys_have_ip(struct sockaddr_in ip)
203 s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
207 ret = bind(s, (struct sockaddr *)&ip, sizeof(ip));
215 /* This function is used to open a raw socket to capture from
217 int ctdb_sys_open_capture_socket(const char *iface, void **private_data)
221 pt=pcap_open_live(iface, 100, 0, 0, NULL);
223 DEBUG(DEBUG_CRIT,("Failed to open capture device %s\n", iface));
226 *((pcap_t **)private_data) = pt;
228 return pcap_fileno(pt);
232 /* This function is used to close the capture socket
234 int ctdb_sys_close_capture_socket(void *private_data)
236 pcap_t *pt = (pcap_t *)private_data;
244 send gratuitous arp reply after we have taken over an ip address
246 saddr is the address we are trying to claim
247 iface is the interface name we will be using to claim the address
249 int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface)
251 /* We dont do grat arp on aix yet */
258 get ethernet MAC address on AIX
260 static int aix_get_mac_addr(const char *device_name, uint8_t mac[6])
263 struct kinfo_ndd *ndd;
266 ksize = getkerninfo(KINFO_NDD, 0, 0, 0);
272 ndd = (struct kinfo_ndd *)malloc(ksize);
278 if (getkerninfo(KINFO_NDD, ndd, &ksize, 0) == -1) {
283 count= ksize/sizeof(struct kinfo_ndd);
284 for (i=0;i<count;i++) {
285 if ( (ndd[i].ndd_type != NDD_ETHER)
286 && (ndd[i].ndd_type != NDD_ISO88023) ) {
289 if (ndd[i].ndd_addrlen != 6) {
292 if (!(ndd[i].ndd_flags&NDD_UP)) {
295 if ( strcmp(device_name, ndd[i].ndd_name)
296 && strcmp(device_name, ndd[i].ndd_alias) ) {
299 memcpy(mac, ndd[i].ndd_addr, 6);
308 int ctdb_sys_read_tcp_packet(int s, void *private_data,
309 struct sockaddr_in *src, struct sockaddr_in *dst,
310 uint32_t *ack_seq, uint32_t *seq)
313 struct ether_header *eth;
316 struct ctdb_killtcp_connection *conn;
317 struct pcap_pkthdr pkthdr;
318 const u_char *buffer;
319 pcap_t *pt = (pcap_t *)private_data;
321 buffer=pcap_next(pt, &pkthdr);
327 eth = (struct ether_header *)buffer;
329 /* We are only interested in IP packets */
330 if (eth->ether_type != htons(ETHERTYPE_IP)) {
335 ip = (struct ip *)(eth+1);
337 /* We only want IPv4 packets */
341 /* Dont look at fragments */
342 if ((ntohs(ip->ip_off)&0x1fff) != 0) {
345 /* we only want TCP */
346 if (ip->ip_p != IPPROTO_TCP) {
350 /* make sure its not a short packet */
351 if (offsetof(struct tcphdr, th_ack) + 4 +
352 (ip->ip_hl*4) > ret) {
356 tcp = (struct tcphdr *)((ip->ip_hl*4) + (char *)ip);
358 /* tell the caller which one we've found */
359 src->sin_addr.s_addr = ip->ip_src.s_addr;
360 src->sin_port = tcp->th_sport;
361 dst->sin_addr.s_addr = ip->ip_dst.s_addr;
362 dst->sin_port = tcp->th_dport;
363 *ack_seq = tcp->th_ack;