2 ctdb system specific code to manage raw sockets on linux
4 Copyright (C) Ronnie Sahlberg 2007
5 Copyright (C) Andrew Tridgell 2007
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, see <http://www.gnu.org/licenses/>.
22 #include "system/network.h"
23 #include "system/filesys.h"
24 #include "system/wait.h"
25 #include "../include/ctdb_private.h"
26 #include "lib/events/events.h"
27 #include <netinet/if_ether.h>
28 #include <net/if_arp.h>
33 send gratuitous arp reply after we have taken over an ip address
35 saddr is the address we are trying to claim
36 iface is the interface name we will be using to claim the address
38 int ctdb_sys_send_arp(const struct sockaddr_in *saddr, const char *iface)
42 struct ether_header *eh;
44 struct ifreq if_hwaddr;
45 unsigned char buffer[64]; /*minimum eth frame size */
50 /* for now, we only handle AF_INET addresses */
51 if (saddr->sin_family != AF_INET) {
52 DEBUG(DEBUG_CRIT,(__location__ " not an ipv4 address (family is %u)\n", saddr->sin_family));
56 s = socket(AF_INET, SOCK_PACKET, htons(ETHERTYPE_ARP));
58 DEBUG(DEBUG_CRIT,(__location__ " failed to open raw socket\n"));
62 /* get the mac address */
63 strcpy(if_hwaddr.ifr_name, iface);
64 ret = ioctl(s, SIOCGIFHWADDR, &if_hwaddr);
67 DEBUG(DEBUG_CRIT,(__location__ " ioctl failed\n"));
70 if (ARPHRD_LOOPBACK == if_hwaddr.ifr_hwaddr.sa_family) {
71 DEBUG(DEBUG_DEBUG,("Ignoring loopback arp request\n"));
75 if (if_hwaddr.ifr_hwaddr.sa_family != AF_LOCAL) {
78 DEBUG(DEBUG_CRIT,(__location__ " not an ethernet address family (0x%x)\n",
79 if_hwaddr.ifr_hwaddr.sa_family));
84 memset(buffer, 0 , 64);
85 eh = (struct ether_header *)buffer;
86 memset(eh->ether_dhost, 0xff, ETH_ALEN);
87 memcpy(eh->ether_shost, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
88 eh->ether_type = htons(ETHERTYPE_ARP);
90 ah = (struct arphdr *)&buffer[sizeof(struct ether_header)];
91 ah->ar_hrd = htons(ARPHRD_ETHER);
92 ah->ar_pro = htons(ETH_P_IP);
93 ah->ar_hln = ETH_ALEN;
96 /* send a gratious arp */
97 ah->ar_op = htons(ARPOP_REQUEST);
99 memcpy(ptr, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
101 memcpy(ptr, &saddr->sin_addr, 4);
103 memset(ptr, 0, ETH_ALEN);
105 memcpy(ptr, &saddr->sin_addr, 4);
108 strncpy(sa.sa_data, iface, sizeof(sa.sa_data));
109 ret = sendto(s, buffer, 64, 0, &sa, sizeof(sa));
112 DEBUG(DEBUG_CRIT,(__location__ " failed sendto\n"));
116 /* send unsolicited arp reply broadcast */
117 ah->ar_op = htons(ARPOP_REPLY);
118 ptr = (char *)&ah[1];
119 memcpy(ptr, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
121 memcpy(ptr, &saddr->sin_addr, 4);
123 memcpy(ptr, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
125 memcpy(ptr, &saddr->sin_addr, 4);
128 strncpy(sa.sa_data, iface, sizeof(sa.sa_data));
129 ret = sendto(s, buffer, 64, 0, &sa, sizeof(sa));
131 DEBUG(DEBUG_CRIT,(__location__ " failed sendto\n"));
141 uint16 checksum for n bytes
143 static uint32_t uint16_checksum(uint16_t *data, size_t n)
147 sum += (uint32_t)ntohs(*data);
152 sum += (uint32_t)ntohs(*(uint8_t *)data);
158 simple TCP checksum - assumes data is multiple of 2 bytes long
160 static uint16_t tcp_checksum(uint16_t *data, size_t n, struct iphdr *ip)
162 uint32_t sum = uint16_checksum(data, n);
164 sum += uint16_checksum((uint16_t *)(void *)&ip->saddr,
166 sum += uint16_checksum((uint16_t *)(void *)&ip->daddr,
168 sum += ip->protocol + n;
169 sum = (sum & 0xFFFF) + (sum >> 16);
170 sum = (sum & 0xFFFF) + (sum >> 16);
180 Send tcp segment from the specified IP/port to the specified
183 This is used to trigger the receiving host into sending its own ACK,
184 which should trigger early detection of TCP reset by the client
187 This can also be used to send RST segments (if rst is true) and also
188 if correct seq and ack numbers are provided.
190 int ctdb_sys_send_tcp(int s,
191 const struct sockaddr_in *dest,
192 const struct sockaddr_in *src,
193 uint32_t seq, uint32_t ack, int rst)
201 /* for now, we only handle AF_INET addresses */
202 if (src->sin_family != AF_INET || dest->sin_family != AF_INET) {
203 DEBUG(DEBUG_CRIT,(__location__ " not an ipv4 address\n"));
209 pkt.ip.ihl = sizeof(pkt.ip)/4;
210 pkt.ip.tot_len = htons(sizeof(pkt));
212 pkt.ip.protocol = IPPROTO_TCP;
213 pkt.ip.saddr = src->sin_addr.s_addr;
214 pkt.ip.daddr = dest->sin_addr.s_addr;
217 pkt.tcp.source = src->sin_port;
218 pkt.tcp.dest = dest->sin_port;
220 pkt.tcp.ack_seq = ack;
225 pkt.tcp.doff = sizeof(pkt.tcp)/4;
226 pkt.tcp.window = htons(1234); /* this makes it easier to spot in a sniffer */
227 pkt.tcp.check = tcp_checksum((uint16_t *)&pkt.tcp, sizeof(pkt.tcp), &pkt.ip);
229 ret = sendto(s, &pkt, sizeof(pkt), 0, dest, sizeof(*dest));
230 if (ret != sizeof(pkt)) {
231 DEBUG(DEBUG_CRIT,(__location__ " failed sendto (%s)\n", strerror(errno)));
240 see if we currently have an interface with the given IP
242 we try to bind to it, and if that fails then we don't have that IP
245 ifname, if non-NULL, will return the name of the interface this ip is tied to
247 bool ctdb_sys_have_ip(struct sockaddr_in ip)
253 s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
257 ret = bind(s, (struct sockaddr *)&ip, sizeof(ip));
264 This function is used to open a raw socket to capture from
266 int ctdb_sys_open_capture_socket(const char *iface, void **private_data)
270 /* Open a socket to capture all traffic */
271 s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
273 DEBUG(DEBUG_CRIT,(__location__ " failed to open raw socket\n"));
278 set_close_on_exec(s);
284 This function is used to do any additional cleanup required when closing
286 Note that the socket itself is closed automatically in the caller.
288 int ctdb_sys_close_capture_socket(void *private_data)
294 This function is used to open a raw socket to send tickles from
296 int ctdb_sys_open_sending_socket(void)
301 s = socket(AF_INET, SOCK_RAW, htons(IPPROTO_RAW));
303 DEBUG(DEBUG_CRIT,(__location__ " failed to open raw socket (%s)\n",
308 ret = setsockopt(s, SOL_IP, IP_HDRINCL, &one, sizeof(one));
310 DEBUG(DEBUG_CRIT,(__location__ " failed to setup IP headers (%s)\n",
317 set_close_on_exec(s);
323 called when the raw socket becomes readable
325 int ctdb_sys_read_tcp_packet(int s, void *private_data,
326 struct sockaddr_in *src, struct sockaddr_in *dst,
327 uint32_t *ack_seq, uint32_t *seq)
330 #define RCVPKTSIZE 100
331 char pkt[RCVPKTSIZE];
332 struct ether_header *eth;
336 ret = recv(s, pkt, RCVPKTSIZE, MSG_TRUNC);
337 if (ret < sizeof(*eth)+sizeof(*ip)) {
342 eth = (struct ether_header *)pkt;
344 /* We only want IP packets */
345 if (ntohs(eth->ether_type) != ETHERTYPE_IP) {
350 ip = (struct iphdr *)(eth+1);
352 /* We only want IPv4 packets */
353 if (ip->version != 4) {
356 /* Dont look at fragments */
357 if ((ntohs(ip->frag_off)&0x1fff) != 0) {
360 /* we only want TCP */
361 if (ip->protocol != IPPROTO_TCP) {
365 /* make sure its not a short packet */
366 if (offsetof(struct tcphdr, ack_seq) + 4 +
367 (ip->ihl*4) + sizeof(*eth) > ret) {
372 tcp = (struct tcphdr *)((ip->ihl*4) + (char *)ip);
374 /* tell the caller which one we've found */
375 src->sin_addr.s_addr = ip->saddr;
376 src->sin_port = tcp->source;
377 dst->sin_addr.s_addr = ip->daddr;
378 dst->sin_port = tcp->dest;
379 *ack_seq = tcp->ack_seq;