/*
uint16 checksum for n bytes
*/
-static uint32_t uint16_checksum(uint16_t *data, size_t n)
+static uint32_t uint16_checksum(uint8_t *data, size_t n)
{
uint32_t sum=0;
+ uint16_t value;
+
while (n>=2) {
- sum += (uint32_t)ntohs(*data);
- data++;
+ memcpy(&value, data, 2);
+ sum += (uint32_t)ntohs(value);
+ data += 2;
n -= 2;
}
if (n == 1) {
- sum += (uint32_t)ntohs(*(uint8_t *)data);
+ sum += (uint32_t)ntohs(*data);
}
return sum;
}
/*
* simple TCP checksum - assumes data is multiple of 2 bytes long
*/
-static uint16_t ip_checksum(uint16_t *data, size_t n, struct ip *ip)
+static uint16_t ip_checksum(uint8_t *data, size_t n, struct ip *ip)
{
uint32_t sum = uint16_checksum(data, n);
uint16_t sum2;
- sum += uint16_checksum((uint16_t *)&ip->ip_src, sizeof(ip->ip_src));
- sum += uint16_checksum((uint16_t *)&ip->ip_dst, sizeof(ip->ip_dst));
+ sum += uint16_checksum((uint8_t *)&ip->ip_src, sizeof(ip->ip_src));
+ sum += uint16_checksum((uint8_t *)&ip->ip_dst, sizeof(ip->ip_dst));
sum += ip->ip_p + n;
sum = (sum & 0xFFFF) + (sum >> 16);
sum = (sum & 0xFFFF) + (sum >> 16);
return sum2;
}
-static uint16_t ip6_checksum(uint16_t *data, size_t n, struct ip6_hdr *ip6)
+static uint16_t ip6_checksum(uint8_t *data, size_t n, struct ip6_hdr *ip6)
{
uint16_t phdr[3];
uint32_t sum = 0;
uint16_t sum2;
uint32_t len;
- sum += uint16_checksum((uint16_t *)(void *)&ip6->ip6_src, 16);
- sum += uint16_checksum((uint16_t *)(void *)&ip6->ip6_dst, 16);
+ sum += uint16_checksum((uint8_t *)&ip6->ip6_src, 16);
+ sum += uint16_checksum((uint8_t *)&ip6->ip6_dst, 16);
len = htonl(n);
phdr[0] = len & UINT16_MAX;
phdr[1] = (len >> 16) & UINT16_MAX;
/* ip6_nxt is only 8 bits, so fits comfortably into a uint16_t */
phdr[2] = htons(ip6->ip6_nxt);
- sum += uint16_checksum(phdr, sizeof(phdr));
+ sum += uint16_checksum((uint8_t *)phdr, sizeof(phdr));
sum += uint16_checksum(data, n);
memcpy(eh->ether_shost, hwaddr, ETH_ALEN);
eh->ether_type = htons(ETHERTYPE_ARP);
- ea = (struct ether_arp *)&buffer[sizeof(struct ether_header)];
+ ea = (struct ether_arp *)(buffer + sizeof(struct ether_header));
ah = &ea->ea_hdr;
ah->ar_hrd = htons(ARPHRD_ETHER);
ah->ar_pro = htons(ETH_P_IP);
ah->ar_hln = ETH_ALEN;
- ah->ar_pln = 4;
+ ah->ar_pln = sizeof(ea->arp_spa);
if (! reply) {
ah->ar_op = htons(ARPOP_REQUEST);
* Ethernet multicast: 33:33:00:00:00:01 (see RFC2464,
* section 7) - note memset 0 above!
*/
- eh->ether_dhost[0] = eh->ether_dhost[1] = 0x33;
+ eh->ether_dhost[0] = 0x33;
+ eh->ether_dhost[1] = 0x33;
eh->ether_dhost[5] = 0x01;
memcpy(eh->ether_shost, hwaddr, ETH_ALEN);
eh->ether_type = htons(ETHERTYPE_IP6);
- ip6 = (struct ip6_hdr *)(eh+1);
- ip6->ip6_vfc = 0x60;
- ip6->ip6_plen = htons(sizeof(*nd_na) +
+ ip6 = (struct ip6_hdr *)(buffer + sizeof(struct ether_header));
+ ip6->ip6_vfc = 6 << 4;
+ ip6->ip6_plen = htons(sizeof(struct nd_neighbor_advert) +
sizeof(struct nd_opt_hdr) +
ETH_ALEN);
ip6->ip6_nxt = IPPROTO_ICMPV6;
return EIO;
}
- nd_na = (struct nd_neighbor_advert *)(ip6+1);
+ nd_na = (struct nd_neighbor_advert *)(buffer +
+ sizeof(struct ether_header) +
+ sizeof(struct ip6_hdr));
nd_na->nd_na_type = ND_NEIGHBOR_ADVERT;
nd_na->nd_na_code = 0;
nd_na->nd_na_flags_reserved = ND_NA_FLAG_OVERRIDE;
nd_na->nd_na_target = addr->sin6_addr;
+
/* Option: Target link-layer address */
- nd_oh = (struct nd_opt_hdr *)(nd_na+1);
+ nd_oh = (struct nd_opt_hdr *)(buffer +
+ sizeof(struct ether_header) +
+ sizeof(struct ip6_hdr) +
+ sizeof(struct nd_neighbor_advert));
nd_oh->nd_opt_type = ND_OPT_TARGET_LINKADDR;
- nd_oh->nd_opt_len = 1;
+ nd_oh->nd_opt_len = 1; /* multiple of 8 octets */
- ea = (struct ether_addr *)(nd_oh+1);
+ ea = (struct ether_addr *)(buffer +
+ sizeof(struct ether_header) +
+ sizeof(struct ip6_hdr) +
+ sizeof(struct nd_neighbor_advert) +
+ sizeof(struct nd_opt_hdr));
memcpy(ea, hwaddr, ETH_ALEN);
- nd_na->nd_na_cksum = ip6_checksum((uint16_t *)nd_na,
+ nd_na->nd_na_cksum = ip6_checksum((uint8_t *)nd_na,
ntohs(ip6->ip6_plen),
ip6);
{
int s;
struct sockaddr_ll sall = {0};
- struct ifreq if_hwaddr = {{{0}}};
+ struct ifreq if_hwaddr = {
+ .ifr_ifru = {
+ .ifru_flags = 0
+ },
+ };
uint8_t buffer[MAX(ARP_BUFFER_SIZE, IP6_NA_BUFFER_SIZE)];
- struct ifreq ifr = {{{0}}};
+ struct ifreq ifr = {
+ .ifr_ifru = {
+ .ifru_flags = 0
+ },
+ };
struct ether_addr *hwaddr = NULL;
struct ether_addr *ether_dhost = NULL;
size_t len = 0;
ðer_dhost,
&len);
if (ret != 0) {
- DBG_ERR("Failed to build IPv6 neighbor advertisment\n");
+ DBG_ERR("Failed to build IPv6 neighbor advertisement\n");
goto fail;
}
#endif /* HAVE_PACKETSOCKET */
+
+#define IP4_TCP_BUFFER_SIZE sizeof(struct ip) + \
+ sizeof(struct tcphdr)
+
+#define IP6_TCP_BUFFER_SIZE sizeof(struct ip6_hdr) + \
+ sizeof(struct tcphdr)
+
+static int tcp4_build(uint8_t *buf,
+ size_t buflen,
+ const struct sockaddr_in *src,
+ const struct sockaddr_in *dst,
+ uint32_t seq,
+ uint32_t ack,
+ int rst,
+ size_t *len)
+{
+ size_t l = IP4_TCP_BUFFER_SIZE;
+ struct {
+ struct ip ip;
+ struct tcphdr tcp;
+ } *ip4pkt;
+
+ if (l != sizeof(*ip4pkt)) {
+ return EMSGSIZE;
+ }
+
+ if (buflen < l) {
+ return EMSGSIZE;
+ }
+
+ ip4pkt = (void *)buf;
+ memset(ip4pkt, 0, l);
+
+ ip4pkt->ip.ip_v = 4;
+ ip4pkt->ip.ip_hl = sizeof(ip4pkt->ip)/sizeof(uint32_t);
+ 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->sin_addr.s_addr;
+ ip4pkt->ip.ip_dst.s_addr = dst->sin_addr.s_addr;
+ ip4pkt->ip.ip_sum = 0;
+
+ ip4pkt->tcp.th_sport = src->sin_port;
+ ip4pkt->tcp.th_dport = dst->sin_port;
+ ip4pkt->tcp.th_seq = seq;
+ ip4pkt->tcp.th_ack = ack;
+ ip4pkt->tcp.th_flags = 0;
+ ip4pkt->tcp.th_flags |= TH_ACK;
+ if (rst) {
+ ip4pkt->tcp.th_flags |= TH_RST;
+ }
+ ip4pkt->tcp.th_off = sizeof(ip4pkt->tcp)/sizeof(uint32_t);
+ /* this makes it easier to spot in a sniffer */
+ ip4pkt->tcp.th_win = htons(1234);
+ ip4pkt->tcp.th_sum = ip_checksum((uint8_t *)&ip4pkt->tcp,
+ sizeof(ip4pkt->tcp),
+ &ip4pkt->ip);
+
+ *len = l;
+ return 0;
+}
+
+static int tcp6_build(uint8_t *buf,
+ size_t buflen,
+ const struct sockaddr_in6 *src,
+ const struct sockaddr_in6 *dst,
+ uint32_t seq,
+ uint32_t ack,
+ int rst,
+ size_t *len)
+{
+ size_t l = IP6_TCP_BUFFER_SIZE;
+ struct {
+ struct ip6_hdr ip6;
+ struct tcphdr tcp;
+ } *ip6pkt;
+
+ if (l != sizeof(*ip6pkt)) {
+ return EMSGSIZE;
+ }
+
+ if (buflen < l) {
+ return EMSGSIZE;
+ }
+
+ ip6pkt = (void *)buf;
+ memset(ip6pkt, 0, l);
+
+ ip6pkt->ip6.ip6_vfc = 6 << 4;
+ ip6pkt->ip6.ip6_plen = htons(sizeof(struct tcphdr));
+ ip6pkt->ip6.ip6_nxt = IPPROTO_TCP;
+ ip6pkt->ip6.ip6_hlim = 64;
+ ip6pkt->ip6.ip6_src = src->sin6_addr;
+ ip6pkt->ip6.ip6_dst = dst->sin6_addr;
+
+ ip6pkt->tcp.th_sport = src->sin6_port;
+ ip6pkt->tcp.th_dport = dst->sin6_port;
+ ip6pkt->tcp.th_seq = seq;
+ ip6pkt->tcp.th_ack = ack;
+ ip6pkt->tcp.th_flags = 0;
+ ip6pkt->tcp.th_flags |= TH_ACK;
+ if (rst) {
+ ip6pkt->tcp.th_flags |= TH_RST;
+ }
+ ip6pkt->tcp.th_off = sizeof(ip6pkt->tcp)/sizeof(uint32_t);
+ /* this makes it easier to spot in a sniffer */
+ ip6pkt->tcp.th_win = htons(1234);
+ ip6pkt->tcp.th_sum = ip6_checksum((uint8_t *)&ip6pkt->tcp,
+ sizeof(ip6pkt->tcp),
+ &ip6pkt->ip6);
+
+ *len = l;
+ return 0;
+}
+
/*
* Send tcp segment from the specified IP/port to the specified
* destination IP/port.
uint32_t ack,
int rst)
{
- int s;
+ uint8_t buf[MAX(IP4_TCP_BUFFER_SIZE, IP6_TCP_BUFFER_SIZE)];
+ size_t len = 0;
int ret;
+ int s;
uint32_t one = 1;
- uint16_t tmpport;
- ctdb_sock_addr *tmpdest;
- struct {
- struct ip ip;
- struct tcphdr tcp;
- } ip4pkt;
- struct {
- struct ip6_hdr ip6;
- struct tcphdr tcp;
- } ip6pkt;
+ struct sockaddr_in6 tmpdest = { 0 };
int saved_errno;
switch (src->ip.sin_family) {
case AF_INET:
- ZERO_STRUCT(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 = 0;
- ip4pkt.tcp.th_flags |= TH_ACK;
- if (rst) {
- ip4pkt.tcp.th_flags |= TH_RST;
+ ret = tcp4_build(buf,
+ sizeof(buf),
+ &src->ip,
+ &dest->ip,
+ seq,
+ ack,
+ rst,
+ &len);
+ if (ret != 0) {
+ DBG_ERR("Failed to build TCP packet (%d)\n", ret);
+ return ret;
}
- ip4pkt.tcp.th_off = sizeof(ip4pkt.tcp)/4;
- /* this makes it easier to spot in a sniffer */
- ip4pkt.tcp.th_win = htons(1234);
- ip4pkt.tcp.th_sum = ip_checksum((uint16_t *)&ip4pkt.tcp,
- sizeof(ip4pkt.tcp),
- &ip4pkt.ip);
/* open a raw socket to send this segment from */
s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
return -1;
}
- ret = sendto(s, &ip4pkt, sizeof(ip4pkt), 0,
+ ret = sendto(s,
+ buf,
+ len,
+ 0,
(const struct sockaddr *)&dest->ip,
sizeof(dest->ip));
saved_errno = errno;
close(s);
- if (ret != sizeof(ip4pkt)) {
+ if (ret == -1) {
D_ERR("Failed sendto (%s)\n", strerror(saved_errno));
return -1;
}
+ if ((size_t)ret != len) {
+ DBG_ERR("Failed sendto - didn't send full packet\n");
+ return -1;
+ }
break;
+
case AF_INET6:
- ZERO_STRUCT(ip6pkt);
- ip6pkt.ip6.ip6_vfc = 0x60;
- ip6pkt.ip6.ip6_plen = htons(20);
- ip6pkt.ip6.ip6_nxt = IPPROTO_TCP;
- ip6pkt.ip6.ip6_hlim = 64;
- ip6pkt.ip6.ip6_src = src->ip6.sin6_addr;
- ip6pkt.ip6.ip6_dst = dest->ip6.sin6_addr;
-
- ip6pkt.tcp.th_sport = src->ip6.sin6_port;
- ip6pkt.tcp.th_dport = dest->ip6.sin6_port;
- ip6pkt.tcp.th_seq = seq;
- ip6pkt.tcp.th_ack = ack;
- ip6pkt.tcp.th_flags = 0;
- ip6pkt.tcp.th_flags |= TH_RST;
- if (rst) {
- ip6pkt.tcp.th_flags |= TH_RST;
+ ret = tcp6_build(buf,
+ sizeof(buf),
+ &src->ip6,
+ &dest->ip6,
+ seq,
+ ack,
+ rst,
+ &len);
+ if (ret != 0) {
+ DBG_ERR("Failed to build TCP packet (%d)\n", ret);
+ return ret;
}
- ip6pkt.tcp.th_off = sizeof(ip6pkt.tcp)/4;
- /* this makes it easier to spot in a sniffer */
- ip6pkt.tcp.th_win = htons(1234);
- ip6pkt.tcp.th_sum = ip6_checksum((uint16_t *)&ip6pkt.tcp,
- sizeof(ip6pkt.tcp),
- &ip6pkt.ip6);
s = socket(AF_INET6, SOCK_RAW, IPPROTO_RAW);
if (s == -1) {
return -1;
}
- /* sendto() don't like if the port is set and the socket is
- in raw mode.
- */
- tmpdest = discard_const(dest);
- tmpport = tmpdest->ip6.sin6_port;
-
- tmpdest->ip6.sin6_port = 0;
- ret = sendto(s, &ip6pkt, sizeof(ip6pkt), 0,
- (const struct sockaddr *)&dest->ip6,
- sizeof(dest->ip6));
+ /*
+ * sendto() on an IPv6 raw socket requires the port to
+ * be either 0 or a protocol value
+ */
+ tmpdest = dest->ip6;
+ tmpdest.sin6_port = 0;
+
+ ret = sendto(s,
+ buf,
+ len,
+ 0,
+ (const struct sockaddr *)&tmpdest,
+ sizeof(tmpdest));
saved_errno = errno;
- tmpdest->ip6.sin6_port = tmpport;
close(s);
-
- if (ret != sizeof(ip6pkt)) {
+ if (ret == -1) {
D_ERR("Failed sendto (%s)\n", strerror(saved_errno));
return -1;
}
+ if ((size_t)ret != len) {
+ DBG_ERR("Failed sendto - didn't send full packet\n");
+ return -1;
+ }
break;
default:
* wscript has checked to make sure that pcap is available if needed.
*/
+static int tcp4_extract(const uint8_t *ip_pkt,
+ size_t pktlen,
+ struct sockaddr_in *src,
+ struct sockaddr_in *dst,
+ uint32_t *ack_seq,
+ uint32_t *seq,
+ int *rst,
+ uint16_t *window)
+{
+ const struct ip *ip;
+ const struct tcphdr *tcp;
+
+ if (pktlen < sizeof(struct ip)) {
+ return EMSGSIZE;
+ }
+
+ ip = (const struct ip *)ip_pkt;
+
+ /* IPv4 only */
+ if (ip->ip_v != 4) {
+ return ENOMSG;
+ }
+ /* Don't look at fragments */
+ if ((ntohs(ip->ip_off)&0x1fff) != 0) {
+ return ENOMSG;
+ }
+ /* TCP only */
+ if (ip->ip_p != IPPROTO_TCP) {
+ return ENOMSG;
+ }
+
+ /* Ensure there is enough of the packet to gather required fields */
+ if (pktlen <
+ (ip->ip_hl * sizeof(uint32_t)) + offsetof(struct tcphdr, th_sum)) {
+ return EMSGSIZE;
+ }
+
+ tcp = (const struct tcphdr *)(ip_pkt + (ip->ip_hl * sizeof(uint32_t)));
+
+ src->sin_family = AF_INET;
+ src->sin_addr.s_addr = ip->ip_src.s_addr;
+ src->sin_port = tcp->th_sport;
+
+ dst->sin_family = AF_INET;
+ 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;
+ if (window != NULL) {
+ *window = tcp->th_win;
+ }
+ if (rst != NULL) {
+ *rst = tcp->th_flags & TH_RST;
+ }
+
+ return 0;
+}
+
+static int tcp6_extract(const uint8_t *ip_pkt,
+ size_t pktlen,
+ struct sockaddr_in6 *src,
+ struct sockaddr_in6 *dst,
+ uint32_t *ack_seq,
+ uint32_t *seq,
+ int *rst,
+ uint16_t *window)
+{
+ const struct ip6_hdr *ip6;
+ const struct tcphdr *tcp;
+
+ /* Ensure there is enough of the packet to gather required fields */
+ if (pktlen < sizeof(struct ip6_hdr) + offsetof(struct tcphdr, th_sum)) {
+ return EMSGSIZE;
+ }
+
+ ip6 = (const struct ip6_hdr *)ip_pkt;
+
+ /* IPv6 only */
+ if ((ip6->ip6_vfc >> 4) != 6){
+ return ENOMSG;
+ }
+
+ /* TCP only */
+ if (ip6->ip6_nxt != IPPROTO_TCP) {
+ return ENOMSG;
+ }
+
+ tcp = (const struct tcphdr *)(ip_pkt + sizeof(struct ip6_hdr));
+
+ src->sin6_family = AF_INET6;
+ src->sin6_port = tcp->th_sport;
+ src->sin6_addr = ip6->ip6_src;
+
+ dst->sin6_family = AF_INET6;
+ dst->sin6_port = tcp->th_dport;
+ dst->sin6_addr = ip6->ip6_dst;
+
+ *ack_seq = tcp->th_ack;
+ *seq = tcp->th_seq;
+ if (window != NULL) {
+ *window = tcp->th_win;
+ }
+ if (rst != NULL) {
+ *rst = tcp->th_flags & TH_RST;
+ }
+
+ return 0;
+}
+
+
#ifdef HAVE_AF_PACKET
/*
int *rst,
uint16_t *window)
{
- int ret;
-#define RCVPKTSIZE 100
- char pkt[RCVPKTSIZE];
+ ssize_t nread;
+ uint8_t pkt[100]; /* Large enough for simple ACK/RST packets */
struct ether_header *eth;
- struct iphdr *ip;
- struct ip6_hdr *ip6;
- struct tcphdr *tcp;
+ int ret;
- ret = recv(s, pkt, RCVPKTSIZE, MSG_TRUNC);
- if (ret < sizeof(*eth)+sizeof(*ip)) {
- return -1;
+ nread = recv(s, pkt, sizeof(pkt), MSG_TRUNC);
+ if (nread == -1) {
+ return errno;
+ }
+ if ((size_t)nread < sizeof(*eth)) {
+ return EMSGSIZE;
}
ZERO_STRUCTP(src);
/* 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;
- }
-
- /* make sure its not a short packet */
- if (offsetof(struct tcphdr, th_ack) + 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->th_sport;
- dst->ip.sin_family = AF_INET;
- dst->ip.sin_addr.s_addr = ip->daddr;
- dst->ip.sin_port = tcp->th_dport;
- *ack_seq = tcp->th_ack;
- *seq = tcp->th_seq;
- if (window != NULL) {
- *window = tcp->th_win;
- }
- if (rst != NULL) {
- *rst = tcp->th_flags & TH_RST;
- }
+ ret = tcp4_extract(pkt + sizeof(struct ether_header),
+ (size_t)nread - sizeof(struct ether_header),
+ &src->ip,
+ &dst->ip,
+ ack_seq,
+ seq,
+ rst,
+ window);
+ return ret;
- return 0;
} 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 *)(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;
- if (window != NULL) {
- *window = tcp->th_win;
- }
- if (rst != NULL) {
- *rst = tcp->th_flags & TH_RST;
- }
-
- return 0;
+ ret = tcp6_extract(pkt + sizeof(struct ether_header),
+ (size_t)nread - sizeof(struct ether_header),
+ &src->ip6,
+ &dst->ip6,
+ ack_seq,
+ seq,
+ rst,
+ window);
+ return ret;
}
- return -1;
+ return ENOMSG;
}
#else /* HAVE_AF_PACKET */
{
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;
const u_char *buffer;
pcap_t *pt = (pcap_t *)private_data;
buffer=pcap_next(pt, &pkthdr);
if (buffer==NULL) {
- return -1;
+ return ENOMSG;
}
ZERO_STRUCTP(src);
/* we want either IPv4 or IPv6 */
if (eth->ether_type == htons(ETHERTYPE_IP)) {
- /* 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;
- }
-
- /* make sure its not a short packet */
- if (offsetof(struct tcphdr, th_ack) + 4 +
- (ip->ip_hl*4) > pkthdr.len) {
- 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;
- if (window != NULL) {
- *window = tcp->th_win;
- }
- if (rst != NULL) {
- *rst = tcp->th_flags & TH_RST;
- }
+ ret = tcp4_extract(buffer + sizeof(struct ether_header),
+ (size_t)(pkthdr.caplen -
+ sizeof(struct ether_header)),
+ &src->ip,
+ &dst->ip,
+ ack_seq,
+ seq,
+ rst,
+ window);
+ return ret;
- return 0;
} 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;
- if (window != NULL) {
- *window = tcp->th_win;
- }
- if (rst != NULL) {
- *rst = tcp->th_flags & TH_RST;
- }
-
- return 0;
+ ret = tcp6_extract(buffer + sizeof(struct ether_header),
+ (size_t)(pkthdr.caplen -
+ sizeof(struct ether_header)),
+ &src->ip6,
+ &dst->ip6,
+ ack_seq,
+ seq,
+ rst,
+ window);
+ return ret;
}
- return -1;
+ return ENOMSG;
}
#endif /* HAVE_AF_PACKET */