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 simple TCP checksum - assumes data is multiple of 2 bytes long
72 static uint16_t tcp_checksum(uint16_t *data
, size_t n
, struct ip
*ip
)
74 uint32_t sum
= uint16_checksum(data
, n
);
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
));
80 sum
= (sum
& 0xFFFF) + (sum
>> 16);
81 sum
= (sum
& 0xFFFF) + (sum
>> 16);
91 Send tcp segment from the specified IP/port to the specified
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
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.
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
)
108 ctdb_sock_addr
*tmpdest
;
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"));
124 s
= socket(AF_INET
, SOCK_RAW
, htons(IPPROTO_RAW
));
126 DEBUG(DEBUG_CRIT
,(" failed to open raw socket (%s)\n",
131 ret
= setsockopt(s
, IPPROTO_IP
, IP_HDRINCL
, &one
, sizeof(one
));
133 DEBUG(DEBUG_CRIT
, (" failed to setup IP headers (%s)\n",
140 set_close_on_exec(s
);
142 memset(&ip4pkt
, 0, sizeof(ip4pkt
));
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;
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
;
158 ip4pkt
.tcp
.th_flags
= TH_RST
;
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
);
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
)));
173 /* This function is used to open a raw socket to capture from
175 int ctdb_sys_open_capture_socket(const char *iface
, void **private_data
)
179 pt
=pcap_open_live(iface
, 100, 0, 0, NULL
);
181 DEBUG(DEBUG_CRIT
,("Failed to open capture device %s\n", iface
));
184 *((pcap_t
**)private_data
) = pt
;
186 return pcap_fileno(pt
);
190 /* This function is used to close the capture socket
192 int ctdb_sys_close_capture_socket(void *private_data
)
194 pcap_t
*pt
= (pcap_t
*)private_data
;
202 send gratuitous arp reply after we have taken over an ip address
204 saddr is the address we are trying to claim
205 iface is the interface name we will be using to claim the address
207 int ctdb_sys_send_arp(const ctdb_sock_addr
*addr
, const char *iface
)
209 /* FIXME AIX: We dont do gratuitous arp yet */
216 get ethernet MAC address on AIX
218 static int aix_get_mac_addr(const char *device_name
, uint8_t mac
[6])
221 struct kinfo_ndd
*ndd
;
224 ksize
= getkerninfo(KINFO_NDD
, 0, 0, 0);
230 ndd
= (struct kinfo_ndd
*)malloc(ksize
);
236 if (getkerninfo(KINFO_NDD
, ndd
, &ksize
, 0) == -1) {
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
) ) {
247 if (ndd
[i
].ndd_addrlen
!= 6) {
250 if (!(ndd
[i
].ndd_flags
&NDD_UP
)) {
253 if ( strcmp(device_name
, ndd
[i
].ndd_name
)
254 && strcmp(device_name
, ndd
[i
].ndd_alias
) ) {
257 memcpy(mac
, ndd
[i
].ndd_addr
, 6);
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
)
271 struct ether_header
*eth
;
275 struct ctdb_killtcp_connection
*conn
;
276 struct pcap_pkthdr pkthdr
;
277 const u_char
*buffer
;
278 pcap_t
*pt
= (pcap_t
*)private_data
;
280 buffer
=pcap_next(pt
, &pkthdr
);
286 eth
= (struct ether_header
*)buffer
;
288 /* we want either IPv4 or IPv6 */
289 if (eth
->ether_type
== htons(ETHERTYPE_IP
)) {
291 ip
= (struct ip
*)(eth
+1);
293 /* We only want IPv4 packets */
297 /* Dont look at fragments */
298 if ((ntohs(ip
->ip_off
)&0x1fff) != 0) {
301 /* we only want TCP */
302 if (ip
->ip_p
!= IPPROTO_TCP
) {
306 /* make sure its not a short packet */
307 if (offsetof(struct tcphdr
, th_ack
) + 4 +
308 (ip
->ip_hl
*4) > ret
) {
312 tcp
= (struct tcphdr
*)((ip
->ip_hl
*4) + (char *)ip
);
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
;
326 #ifndef ETHERTYPE_IP6
327 #define ETHERTYPE_IP6 0x86dd
329 } else if (eth
->ether_type
== htons(ETHERTYPE_IP6
)) {
331 ip6
= (struct ip6_hdr
*)(eth
+1);
333 /* we only want TCP */
334 if (ip6
->ip6_nxt
!= IPPROTO_TCP
) {
339 tcp
= (struct tcphdr
*)(ip6
+1);
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
;
346 dst
->ip6
.sin6_family
= AF_INET6
;
347 dst
->ip6
.sin6_port
= tcp
->th_dport
;
348 dst
->ip6
.sin6_addr
= ip6
->ip6_dst
;
350 *ack_seq
= tcp
->th_ack
;
360 bool ctdb_sys_check_iface_exists(const char *iface
)
362 /* FIXME AIX: Interface always considered present */
366 int ctdb_get_peer_pid(const int fd
, pid_t
*peer_pid
)
368 struct peercred_struct cr
;
369 socklen_t crl
= sizeof(struct peercred_struct
);
371 if ((ret
= getsockopt(fd
, SOL_SOCKET
, SO_PEERID
, &cr
, &crl
) == 0)) {
377 char *ctdb_get_process_name(pid_t pid
)
379 /* FIXME AIX: get_process_name not implemented */
383 int ctdb_set_process_name(const char *name
)
385 /* FIXME AIX: set_process_name not implemented */
389 bool ctdb_get_lock_info(pid_t req_pid
, struct ctdb_lock_info
*lock_info
)
391 /* FIXME AIX: get_lock_info not implemented */
395 bool ctdb_get_blocker_pid(struct ctdb_lock_info
*reqlock
, pid_t
*blocker_pid
)
397 /* FIXME AIX: get_blocker_pid not implemented */