ctdb-common: Protocol argument must be in host order for socket() call
[samba.git] / ctdb / common / system_aix.c
index 0587e83f03289d1e79727a4138ab4479e773855b..2d35a229aade570aff6f65e92b4f08aa268fca88 100644 (file)
 */
 
 
-#include "includes.h"
+#include "replace.h"
 #include "system/network.h"
 #include "system/filesys.h"
 #include "system/wait.h"
+
+#include "lib/util/debug.h"
+
+#include "protocol/protocol.h"
+
 #include <netinet/if_ether.h>
-#include "../include/ctdb_private.h"
+#include <netinet/ip6.h>
+#include <net/if_arp.h>
 #include <sys/ndd_var.h>
 #include <sys/kinfo.h>
 #include <pcap.h>
 
+#include "common/logging.h"
+#include "common/system.h"
 
 
+#if 0
+This function is no longer used and its code should be moved into
+send tcp packet   after that function has been enhanced to do ipv6 as well.
 
 /* This function is used to open a raw socket to send tickles from
  */
@@ -39,16 +50,16 @@ int ctdb_sys_open_sending_socket(void)
        int s, ret;
        uint32_t one = 1;
 
-       s = socket(AF_INET, SOCK_RAW, htons(IPPROTO_RAW));
+       s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
        if (s == -1) {
-               DEBUG(0,(" failed to open raw socket (%s)\n",
+               DEBUG(DEBUG_CRIT,(" failed to open raw socket (%s)\n",
                         strerror(errno)));
                return -1;
        }
 
        ret = setsockopt(s, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one));
        if (ret != 0) {
-               DEBUG(0,(" failed to setup IP headers (%s)\n",
+               DEBUG(DEBUG_CRIT, (" failed to setup IP headers (%s)\n",
                         strerror(errno)));
                close(s);
                return -1;
@@ -59,24 +70,7 @@ int ctdb_sys_open_sending_socket(void)
 
        return s;
 }
-
-
-/*
-  uint16 checksum for n bytes
- */
-static uint32_t uint16_checksum(uint16_t *data, size_t n)
-{
-       uint32_t sum=0;
-       while (n>=2) {
-               sum += (uint32_t)ntohs(*data);
-               data++;
-               n -= 2;
-       }
-       if (n == 1) {
-               sum += (uint32_t)ntohs(*(uint8_t *)data);
-       }
-       return sum;
-}
+#endif
 
 /*
   simple TCP checksum - assumes data is multiple of 2 bytes long
@@ -110,85 +104,77 @@ static uint16_t tcp_checksum(uint16_t *data, size_t n, struct ip *ip)
   This can also be used to send RST segments (if rst is true) and also
   if correct seq and ack numbers are provided.
  */
-int ctdb_sys_send_tcp(int s,
-                     const struct sockaddr_in *dest, 
-                     const struct sockaddr_in *src,
+int ctdb_sys_send_tcp(const ctdb_sock_addr *dest,
+                     const ctdb_sock_addr *src,
                      uint32_t seq, uint32_t ack, int rst)
 {
-       int ret;
+       int s;
+       int ret;
+       uint32_t one = 1;
+       ctdb_sock_addr *tmpdest;
+       
        struct {
                struct ip ip;
                struct tcphdr tcp;
-       } pkt;
+       } ip4pkt;
+
 
        /* for now, we only handle AF_INET addresses */
-       if (src->sin_family != AF_INET || dest->sin_family != AF_INET) {
-               DEBUG(0,(__location__ " not an ipv4 address\n"));
+       if (src->ip.sin_family != AF_INET || dest->ip.sin_family != AF_INET) {
+               DEBUG(DEBUG_CRIT,(__location__ " not an ipv4 address\n"));
                return -1;
        }
 
-       memset(&pkt, 0, sizeof(pkt));
-       pkt.ip.ip_v     = 4;
-       pkt.ip.ip_hl    = sizeof(pkt.ip)/4;
-       pkt.ip.ip_len   = htons(sizeof(pkt));
-       pkt.ip.ip_ttl   = 255;
-       pkt.ip.ip_p     = IPPROTO_TCP;
-       pkt.ip.ip_src.s_addr   = src->sin_addr.s_addr;
-       pkt.ip.ip_dst.s_addr   = dest->sin_addr.s_addr;
-       pkt.ip.ip_sum   = 0;
-
-       pkt.tcp.th_sport   = src->sin_port;
-       pkt.tcp.th_dport     = dest->sin_port;
-       pkt.tcp.th_seq      = seq;
-       pkt.tcp.th_ack    = ack;
-       pkt.tcp.th_flags  = TH_ACK;
-       if (rst) {
-               pkt.tcp.th_flags      = TH_RST;
-       }
-       pkt.tcp.th_off    = sizeof(pkt.tcp)/4;
-       pkt.tcp.th_win   = htons(1234);
-       pkt.tcp.th_sum    = tcp_checksum((uint16_t *)&pkt.tcp, sizeof(pkt.tcp), &pkt.ip);
 
-       ret = sendto(s, &pkt, sizeof(pkt), 0, (struct sockaddr *)dest, sizeof(*dest));
-       if (ret != sizeof(pkt)) {
-               DEBUG(0,(__location__ " failed sendto (%s)\n", strerror(errno)));
+
+       s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
+       if (s == -1) {
+               DEBUG(DEBUG_CRIT,(" failed to open raw socket (%s)\n",
+                        strerror(errno)));
                return -1;
        }
 
-       return 0;
-}
-
-
-/*
-  see if we currently have an interface with the given IP
+       ret = setsockopt(s, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one));
+       if (ret != 0) {
+               DEBUG(DEBUG_CRIT, (" failed to setup IP headers (%s)\n",
+                        strerror(errno)));
+               close(s);
+               return -1;
+       }
 
-  we try to bind to it, and if that fails then we don't have that IP
-  on an interface
- */
-bool ctdb_sys_have_ip(const char *ip, bool *is_loopback, TALLOC_CTX *mem_ctx, char **ifname)
-{
-       struct sockaddr_in sin;
-       int s;
-       int ret;
+       set_nonblocking(s);
+       set_close_on_exec(s);
 
-       if (is_loopback) {
-               DEBUG(0,(__location__ " NOT IMPLEMENTED YET: ctdb_sys_have_ip() does not yet support is_loopback on AIX. This needs to be implemented similar to system_linux.c\n"));
+       memset(&ip4pkt, 0, sizeof(ip4pkt));
+       ip4pkt.ip.ip_v     = 4;
+       ip4pkt.ip.ip_hl    = sizeof(ip4pkt.ip)/4;
+       ip4pkt.ip.ip_len   = htons(sizeof(ip4pkt));
+       ip4pkt.ip.ip_ttl   = 255;
+       ip4pkt.ip.ip_p     = IPPROTO_TCP;
+       ip4pkt.ip.ip_src.s_addr   = src->ip.sin_addr.s_addr;
+       ip4pkt.ip.ip_dst.s_addr   = dest->ip.sin_addr.s_addr;
+       ip4pkt.ip.ip_sum   = 0;
+
+       ip4pkt.tcp.th_sport   = src->ip.sin_port;
+       ip4pkt.tcp.th_dport     = dest->ip.sin_port;
+       ip4pkt.tcp.th_seq      = seq;
+       ip4pkt.tcp.th_ack    = ack;
+       ip4pkt.tcp.th_flags  = TH_ACK;
+       if (rst) {
+               ip4pkt.tcp.th_flags      = TH_RST;
        }
+       ip4pkt.tcp.th_off    = sizeof(ip4pkt.tcp)/4;
+       ip4pkt.tcp.th_win   = htons(1234);
+       ip4pkt.tcp.th_sum    = tcp_checksum((uint16_t *)&ip4pkt.tcp, sizeof(ip4pkt.tcp), &ip4pkt.ip);
 
-       sin.sin_port = 0;
-       inet_aton(ip, &sin.sin_addr);
-       sin.sin_family = AF_INET;
-       s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
-       if (s == -1) {
-               return false;
+       ret = sendto(s, &ip4pkt, sizeof(ip4pkt), 0, (struct sockaddr *)dest, sizeof(*dest));
+       if (ret != sizeof(ip4pkt)) {
+               DEBUG(DEBUG_CRIT,(__location__ " failed sendto (%s)\n", strerror(errno)));
+               return -1;
        }
-       ret = bind(s, (struct sockaddr *)&sin, sizeof(sin));
-       close(s);
-       return ret == 0;
-}
-
-
 
+       return 0;
+}
 
 /* This function is used to open a raw socket to capture from
  */
@@ -198,7 +184,7 @@ int ctdb_sys_open_capture_socket(const char *iface, void **private_data)
 
        pt=pcap_open_live(iface, 100, 0, 0, NULL);
        if (pt == NULL) {
-               DEBUG(0,("Failed to open capture device %s\n", iface));
+               DEBUG(DEBUG_CRIT,("Failed to open capture device %s\n", iface));
                return -1;
        }
        *((pcap_t **)private_data) = pt;
@@ -224,10 +210,10 @@ int ctdb_sys_close_capture_socket(void *private_data)
   saddr is the address we are trying to claim
   iface is the interface name we will be using to claim the address
  */
-int ctdb_sys_send_arp(const struct sockaddr_in *saddr, const char *iface)
+int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface)
 {
-       /* We dont do grat arp on aix yet */
-       return 0;
+       /* FIXME AIX: We don't do gratuitous arp yet */
+       return -1;
 }
 
 
@@ -284,12 +270,13 @@ static int aix_get_mac_addr(const char *device_name, uint8_t mac[6])
 }
 
 int ctdb_sys_read_tcp_packet(int s, void *private_data, 
-                       struct sockaddr_in *src, struct sockaddr_in *dst,
+                       ctdb_sock_addr *src, ctdb_sock_addr *dst,
                        uint32_t *ack_seq, uint32_t *seq)
 {
        int ret;
        struct ether_header *eth;
        struct ip *ip;
+       struct ip6_hdr *ip6;
        struct tcphdr *tcp;
        struct ctdb_killtcp_connection *conn;
        struct pcap_pkthdr pkthdr;
@@ -304,45 +291,91 @@ int ctdb_sys_read_tcp_packet(int s, void *private_data,
        /* Ethernet */
        eth = (struct ether_header *)buffer;
 
-       /* We are only interested in IP packets */
-       if (eth->ether_type != htons(ETHERTYPE_IP)) {
-               return -1;
-       }
+       /* we want either IPv4 or IPv6 */
+       if (eth->ether_type == htons(ETHERTYPE_IP)) {
+               /* IP */
+               ip = (struct ip *)(eth+1);
 
-       /* IP */
-       ip = (struct ip *)(eth+1);
+               /* We only want IPv4 packets */
+               if (ip->ip_v != 4) {
+                       return -1;
+               }
+               /* Dont look at fragments */
+               if ((ntohs(ip->ip_off)&0x1fff) != 0) {
+                       return -1;
+               }
+               /* we only want TCP */
+               if (ip->ip_p != IPPROTO_TCP) {
+                       return -1;
+               }
 
-       /* We only want IPv4 packets */
-       if (ip->ip_v != 4) {
-               return -1;
-       }
-       /* Dont look at fragments */
-       if ((ntohs(ip->ip_off)&0x1fff) != 0) {
-               return -1;
-       }
-       /* we only want TCP */
-       if (ip->ip_p != IPPROTO_TCP) {
-               return -1;
-       }
+               /* make sure its not a short packet */
+               if (offsetof(struct tcphdr, th_ack) + 4 + 
+                   (ip->ip_hl*4) > ret) {
+                       return -1;
+               }
+               /* TCP */
+               tcp = (struct tcphdr *)((ip->ip_hl*4) + (char *)ip);
+       
+               /* tell the caller which one we've found */
+               src->ip.sin_family      = AF_INET;
+               src->ip.sin_addr.s_addr = ip->ip_src.s_addr;
+               src->ip.sin_port        = tcp->th_sport;
+               dst->ip.sin_family      = AF_INET;
+               dst->ip.sin_addr.s_addr = ip->ip_dst.s_addr;
+               dst->ip.sin_port        = tcp->th_dport;
+               *ack_seq                = tcp->th_ack;
+               *seq                    = tcp->th_seq;
 
-       /* make sure its not a short packet */
-       if (offsetof(struct tcphdr, th_ack) + 4 + 
-           (ip->ip_hl*4) > ret) {
-               return -1;
+
+               return 0;
+#ifndef ETHERTYPE_IP6
+#define ETHERTYPE_IP6 0x86dd
+#endif
+       } else if (eth->ether_type == htons(ETHERTYPE_IP6)) {
+                       /* IP6 */
+               ip6 = (struct ip6_hdr *)(eth+1);
+
+               /* we only want TCP */
+               if (ip6->ip6_nxt != IPPROTO_TCP) {
+                       return -1;
+               }
+
+               /* TCP */
+               tcp = (struct tcphdr *)(ip6+1);
+
+               /* tell the caller which one we've found */
+               src->ip6.sin6_family = AF_INET6;
+               src->ip6.sin6_port   = tcp->th_sport;
+               src->ip6.sin6_addr   = ip6->ip6_src;
+
+               dst->ip6.sin6_family = AF_INET6;
+               dst->ip6.sin6_port   = tcp->th_dport;
+               dst->ip6.sin6_addr   = ip6->ip6_dst;
+
+               *ack_seq             = tcp->th_ack;
+               *seq                 = tcp->th_seq;
+
+               return 0;
        }
-       /* TCP */
-       tcp = (struct tcphdr *)((ip->ip_hl*4) + (char *)ip);
-       
-       /* tell the caller which one we've found */
-       src->sin_addr.s_addr = ip->ip_src.s_addr;
-       src->sin_port        = tcp->th_sport;
-       dst->sin_addr.s_addr = ip->ip_dst.s_addr;
-       dst->sin_port        = tcp->th_dport;
-       *ack_seq             = tcp->th_ack;
-       *seq                 = tcp->th_seq;
 
-       return 0;
+       return -1;
 }
 
 
+bool ctdb_sys_check_iface_exists(const char *iface)
+{
+       /* FIXME AIX: Interface always considered present */
+       return true;
+}
 
+int ctdb_get_peer_pid(const int fd, pid_t *peer_pid)
+{
+       struct peercred_struct cr;
+       socklen_t crl = sizeof(struct peercred_struct);
+       int ret;
+       if ((ret = getsockopt(fd, SOL_SOCKET, SO_PEERID, &cr, &crl) == 0)) {
+               *peer_pid = cr.pid;
+       }
+       return ret;
+}