summaryrefslogtreecommitdiffstats
path: root/ctdb/common/system_linux.c
diff options
context:
space:
mode:
Diffstat (limited to 'ctdb/common/system_linux.c')
-rw-r--r--ctdb/common/system_linux.c108
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;
}