diff options
Diffstat (limited to 'ctdb/common/system_linux.c')
-rw-r--r-- | ctdb/common/system_linux.c | 108 |
1 files changed, 69 insertions, 39 deletions
diff --git a/ctdb/common/system_linux.c b/ctdb/common/system_linux.c index 32db545b09f..760877fe3ad 100644 --- a/ctdb/common/system_linux.c +++ b/ctdb/common/system_linux.c @@ -344,17 +344,17 @@ int ctdb_sys_send_tcp(const ctdb_sock_addr *dest, ifname, if non-NULL, will return the name of the interface this ip is tied to */ -bool ctdb_sys_have_ip(struct sockaddr_in ip) +bool ctdb_sys_have_ip(ctdb_sock_addr *addr) { int s; int ret; - ip.sin_port = 0; - s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + addr->ip.sin_port = 0; + s = socket(addr->sa.sa_family, SOCK_STREAM, IPPROTO_TCP); if (s == -1) { return false; } - ret = bind(s, (struct sockaddr *)&ip, sizeof(ip)); + ret = bind(s, (struct sockaddr *)addr, sizeof(ctdb_sock_addr)); close(s); return ret == 0; @@ -395,7 +395,7 @@ int ctdb_sys_close_capture_socket(void *private_data) called when the raw socket becomes readable */ 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; @@ -403,6 +403,7 @@ int ctdb_sys_read_tcp_packet(int s, void *private_data, char pkt[RCVPKTSIZE]; struct ether_header *eth; struct iphdr *ip; + struct ip6_hdr *ip6; struct tcphdr *tcp; ret = recv(s, pkt, RCVPKTSIZE, MSG_TRUNC); @@ -413,45 +414,74 @@ int ctdb_sys_read_tcp_packet(int s, void *private_data, /* Ethernet */ eth = (struct ether_header *)pkt; - /* We only want IP packets */ - if (ntohs(eth->ether_type) != ETHERTYPE_IP) { - return -1; - } - - /* IP */ - ip = (struct iphdr *)(eth+1); + /* we want either IPv4 or IPv6 */ + if (ntohs(eth->ether_type) == ETHERTYPE_IP) { + /* IP */ + ip = (struct iphdr *)(eth+1); - /* We only want IPv4 packets */ - if (ip->version != 4) { - return -1; - } - /* Dont look at fragments */ - if ((ntohs(ip->frag_off)&0x1fff) != 0) { - return -1; - } - /* we only want TCP */ - if (ip->protocol != IPPROTO_TCP) { - return -1; - } + /* We only want IPv4 packets */ + if (ip->version != 4) { + return -1; + } + /* Dont look at fragments */ + if ((ntohs(ip->frag_off)&0x1fff) != 0) { + return -1; + } + /* we only want TCP */ + if (ip->protocol != IPPROTO_TCP) { + return -1; + } - /* make sure its not a short packet */ - if (offsetof(struct tcphdr, ack_seq) + 4 + - (ip->ihl*4) + sizeof(*eth) > ret) { - return -1; - } + /* make sure its not a short packet */ + if (offsetof(struct tcphdr, ack_seq) + 4 + + (ip->ihl*4) + sizeof(*eth) > ret) { + return -1; + } + /* TCP */ + tcp = (struct tcphdr *)((ip->ihl*4) + (char *)ip); + + /* tell the caller which one we've found */ + src->ip.sin_family = AF_INET; + src->ip.sin_addr.s_addr = ip->saddr; + src->ip.sin_port = tcp->source; + dst->ip.sin_family = AF_INET; + dst->ip.sin_addr.s_addr = ip->daddr; + dst->ip.sin_port = tcp->dest; + *ack_seq = tcp->ack_seq; + *seq = tcp->seq; + + return 0; +#ifndef ETHERTYPE_IP6 +#define ETHERTYPE_IP6 0x86dd +#endif + } else if (ntohs(eth->ether_type) == 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 *)((ip->ihl*4) + (char *)ip); + /* TCP */ + tcp = (struct tcphdr *)(ip6+1); - /* tell the caller which one we've found */ - src->sin_addr.s_addr = ip->saddr; - src->sin_port = tcp->source; - dst->sin_addr.s_addr = ip->daddr; - dst->sin_port = tcp->dest; - *ack_seq = tcp->ack_seq; - *seq = tcp->seq; + /* tell the caller which one we've found */ + src->ip6.sin6_family = AF_INET6; + src->ip6.sin6_port = tcp->source; + src->ip6.sin6_addr = ip6->ip6_src; - return 0; + dst->ip6.sin6_family = AF_INET6; + dst->ip6.sin6_port = tcp->source; + dst->ip6.sin6_addr = ip6->ip6_dst; + + *ack_seq = tcp->ack_seq; + *seq = tcp->seq; + + return 0; + } + + return -1; } |