#include "system/network.h"
#include "system/filesys.h"
#include "system/wait.h"
-#include <netinet/if_ether.h>
#include "../include/ctdb_private.h"
+#include <netinet/if_ether.h>
+#include <netinet/ip6.h>
+#include <net/if_arp.h>
#include <sys/ndd_var.h>
#include <sys/kinfo.h>
#include <pcap.h>
}
#endif
-/*
- 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;
-}
-
/*
simple TCP checksum - assumes data is multiple of 2 bytes long
*/
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) {
+ 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(DEBUG_CRIT,(__location__ " failed sendto (%s)\n", strerror(errno)));
+
+ s = socket(AF_INET, SOCK_RAW, htons(IPPROTO_RAW));
+ if (s == -1) {
+ DEBUG(DEBUG_CRIT,(" failed to open raw socket (%s)\n",
+ strerror(errno)));
return -1;
}
- return 0;
-}
-
+ 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;
+ }
-/*
- see if we currently have an interface with the given IP
+ set_nonblocking(s);
+ set_close_on_exec(s);
- 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(struct sockaddr_in ip)
-{
- int s;
- int ret;
-
- ip.sin_port = 0;
- s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (s == -1) {
- return false;
+ 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;
}
- ret = bind(s, (struct sockaddr *)&ip, sizeof(ip));
- close(s);
- return ret == 0;
-}
-
+ 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);
+ 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;
+ }
+ return 0;
+}
/* This function is used to open a raw socket to capture from
*/
}
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;
/* 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;
}