along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#include "includes.h"
+#include "replace.h"
#include "system/network.h"
#include "system/filesys.h"
#include "system/wait.h"
-#include "../include/ctdb_private.h"
-#include "lib/events/events.h"
+
+#include "lib/util/debug.h"
+
+#include "ctdb_private.h"
+
#include <netinet/if_ether.h>
#include <netinet/ip6.h>
#include <netinet/icmp6.h>
#include <net/if_arp.h>
+#include <netpacket/packet.h>
+#include <sys/prctl.h>
+#include "common/logging.h"
+#include "common/system.h"
#ifndef ETHERTYPE_IP6
#define ETHERTYPE_IP6 0x86dd
#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;
-}
-
/*
calculate the tcp checksum for tcp over ipv6
*/
int ctdb_sys_send_arp(const ctdb_sock_addr *addr, const char *iface)
{
int s, ret;
- struct sockaddr sa;
+ struct sockaddr_ll sall;
struct ether_header *eh;
struct arphdr *ah;
struct ip6_hdr *ip6;
- struct icmp6_hdr *icmp6;
+ struct nd_neighbor_advert *nd_na;
+ struct nd_opt_hdr *nd_oh;
struct ifreq if_hwaddr;
- unsigned char buffer[78]; /* ipv6 neigh solicitation size */
+ /* Size of IPv6 neighbor advertisement (with option) */
+ unsigned char buffer[sizeof(struct ether_header) +
+ sizeof(struct ip6_hdr) +
+ sizeof(struct nd_neighbor_advert) +
+ sizeof(struct nd_opt_hdr) + ETH_ALEN];
char *ptr;
+ char bdcast[] = {0xff,0xff,0xff,0xff,0xff,0xff};
+ struct ifreq ifr;
- ZERO_STRUCT(sa);
+ ZERO_STRUCT(sall);
+ ZERO_STRUCT(ifr);
+ ZERO_STRUCT(if_hwaddr);
switch (addr->ip.sin_family) {
case AF_INET:
- s = socket(AF_INET, SOCK_PACKET, htons(ETHERTYPE_ARP));
+ s = socket(PF_PACKET, SOCK_RAW, htons(ETHERTYPE_ARP));
if (s == -1){
DEBUG(DEBUG_CRIT,(__location__ " failed to open raw socket\n"));
return -1;
}
+ DEBUG(DEBUG_DEBUG, (__location__ " Created SOCKET FD:%d for sending arp\n", s));
+ strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
+ if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
+ DEBUG(DEBUG_CRIT,(__location__ " interface '%s' not found\n", iface));
+ close(s);
+ return -1;
+ }
+
/* get the mac address */
- strcpy(if_hwaddr.ifr_name, iface);
+ strncpy(if_hwaddr.ifr_name, iface, sizeof(if_hwaddr.ifr_name)-1);
ret = ioctl(s, SIOCGIFHWADDR, &if_hwaddr);
if ( ret < 0 ) {
close(s);
memcpy(ptr, &addr->ip.sin_addr, 4);
ptr+=4;
- strncpy(sa.sa_data, iface, sizeof(sa.sa_data));
- ret = sendto(s, buffer, 64, 0, &sa, sizeof(sa));
+ sall.sll_family = AF_PACKET;
+ sall.sll_halen = 6;
+ memcpy(&sall.sll_addr[0], bdcast, sall.sll_halen);
+ sall.sll_protocol = htons(ETH_P_ALL);
+ sall.sll_ifindex = ifr.ifr_ifindex;
+ ret = sendto(s, buffer, 64, 0, (struct sockaddr *)&sall, sizeof(sall));
if (ret < 0 ){
close(s);
DEBUG(DEBUG_CRIT,(__location__ " failed sendto\n"));
memcpy(ptr, &addr->ip.sin_addr, 4);
ptr+=4;
- strncpy(sa.sa_data, iface, sizeof(sa.sa_data));
- ret = sendto(s, buffer, 64, 0, &sa, sizeof(sa));
+ ret = sendto(s, buffer, 64, 0, (struct sockaddr *)&sall, sizeof(sall));
if (ret < 0 ){
DEBUG(DEBUG_CRIT,(__location__ " failed sendto\n"));
+ close(s);
return -1;
}
close(s);
break;
case AF_INET6:
- s = socket(AF_INET, SOCK_PACKET, htons(ETHERTYPE_IP6));
+ s = socket(PF_PACKET, SOCK_RAW, htons(ETHERTYPE_ARP));
if (s == -1){
DEBUG(DEBUG_CRIT,(__location__ " failed to open raw socket\n"));
return -1;
}
+ DEBUG(DEBUG_DEBUG, (__location__ " Created SOCKET FD:%d for sending arp\n", s));
+ strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
+ if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
+ DEBUG(DEBUG_CRIT,(__location__ " interface '%s' not found\n", iface));
+ close(s);
+ return -1;
+ }
+
/* get the mac address */
- strcpy(if_hwaddr.ifr_name, iface);
+ strncpy(if_hwaddr.ifr_name, iface, sizeof(if_hwaddr.ifr_name)-1);
ret = ioctl(s, SIOCGIFHWADDR, &if_hwaddr);
if ( ret < 0 ) {
close(s);
memset(buffer, 0 , sizeof(buffer));
eh = (struct ether_header *)buffer;
- memset(eh->ether_dhost, 0xff, ETH_ALEN);
+ /* Ethernet multicast: 33:33:00:00:00:01 (see RFC2464,
+ * section 7) - note zeroes above! */
+ eh->ether_dhost[0] = eh->ether_dhost[1] = 0x33;
+ eh->ether_dhost[5] = 0x01;
memcpy(eh->ether_shost, if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
eh->ether_type = htons(ETHERTYPE_IP6);
ip6 = (struct ip6_hdr *)(eh+1);
ip6->ip6_vfc = 0x60;
- ip6->ip6_plen = htons(24);
+ ip6->ip6_plen = htons(sizeof(*nd_na) +
+ sizeof(struct nd_opt_hdr) +
+ ETH_ALEN);
ip6->ip6_nxt = IPPROTO_ICMPV6;
ip6->ip6_hlim = 255;
- ip6->ip6_dst = addr->ip6.sin6_addr;
-
- icmp6 = (struct icmp6_hdr *)(ip6+1);
- icmp6->icmp6_type = ND_NEIGHBOR_SOLICIT;
- icmp6->icmp6_code = 0;
- memcpy(&icmp6->icmp6_data32[1], &addr->ip6.sin6_addr, 16);
-
- icmp6->icmp6_cksum = tcp_checksum6((uint16_t *)icmp6, ntohs(ip6->ip6_plen), ip6);
-
- strncpy(sa.sa_data, iface, sizeof(sa.sa_data));
- ret = sendto(s, buffer, 78, 0, &sa, sizeof(sa));
+ ip6->ip6_src = addr->ip6.sin6_addr;
+ /* all-nodes multicast */
+ inet_pton(AF_INET6, "ff02::1", &ip6->ip6_dst);
+
+ nd_na = (struct nd_neighbor_advert *)(ip6+1);
+ 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->ip6.sin6_addr;
+ /* Option: Target link-layer address */
+ nd_oh = (struct nd_opt_hdr *)(nd_na+1);
+ nd_oh->nd_opt_type = ND_OPT_TARGET_LINKADDR;
+ nd_oh->nd_opt_len = 1;
+ memcpy(&(nd_oh+1)[0], if_hwaddr.ifr_hwaddr.sa_data, ETH_ALEN);
+
+ nd_na->nd_na_cksum = tcp_checksum6((uint16_t *)nd_na,
+ ntohs(ip6->ip6_plen), ip6);
+
+ sall.sll_family = AF_PACKET;
+ sall.sll_halen = 6;
+ memcpy(&sall.sll_addr[0], &eh->ether_dhost[0], sall.sll_halen);
+ sall.sll_protocol = htons(ETH_P_ALL);
+ sall.sll_ifindex = ifr.ifr_ifindex;
+ ret = sendto(s, buffer, sizeof(buffer),
+ 0, (struct sockaddr *)&sall, sizeof(sall));
if (ret < 0 ){
close(s);
DEBUG(DEBUG_CRIT,(__location__ " failed sendto\n"));
set_nonblocking(s);
set_close_on_exec(s);
- ret = sendto(s, &ip4pkt, sizeof(ip4pkt), 0, &dest->ip, sizeof(dest->ip));
+ ret = sendto(s, &ip4pkt, sizeof(ip4pkt), 0,
+ (const struct sockaddr *)&dest->ip,
+ sizeof(dest->ip));
close(s);
if (ret != sizeof(ip4pkt)) {
DEBUG(DEBUG_CRIT,(__location__ " failed sendto (%s)\n", strerror(errno)));
return -1;
}
- /* sendto() dont like if the port is set and the socket is
+ /* 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, &dest->ip6, sizeof(dest->ip6));
+ ret = sendto(s, &ip6pkt, sizeof(ip6pkt), 0,
+ (const struct sockaddr *)&dest->ip6,
+ sizeof(dest->ip6));
tmpdest->ip6.sin6_port = tmpport;
close(s);
return 0;
}
-
-/*
- see if we currently have an interface with the given IP
-
- we try to bind to it, and if that fails then we don't have that IP
- on an interface
-
- ifname, if non-NULL, will return the name of the interface this ip is tied to
- */
-bool ctdb_sys_have_ip(ctdb_sock_addr *addr)
-{
- int s;
- int ret;
-
- 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 *)addr, sizeof(ctdb_sock_addr));
-
- close(s);
- return ret == 0;
-}
-
/*
This function is used to open a raw socket to capture from
*/
return -1;
}
+ DEBUG(DEBUG_DEBUG, (__location__ " Created RAW SOCKET FD:%d for tcp tickle\n", s));
+
set_nonblocking(s);
set_close_on_exec(s);
}
+bool ctdb_sys_check_iface_exists(const char *iface)
+{
+ int s;
+ struct ifreq ifr;
+
+ s = socket(PF_PACKET, SOCK_RAW, 0);
+ if (s == -1){
+ /* We don't know if the interface exists, so assume yes */
+ DEBUG(DEBUG_CRIT,(__location__ " failed to open raw socket\n"));
+ return true;
+ }
+
+ strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name)-1);
+ if (ioctl(s, SIOCGIFINDEX, &ifr) < 0 && errno == ENODEV) {
+ DEBUG(DEBUG_CRIT,(__location__ " interface '%s' not found\n", iface));
+ close(s);
+ return false;
+ }
+ close(s);
+
+ return true;
+}
+
+int ctdb_get_peer_pid(const int fd, pid_t *peer_pid)
+{
+ struct ucred cr;
+ socklen_t crl = sizeof(struct ucred);
+ int ret;
+ if ((ret = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cr, &crl) == 0)) {
+ *peer_pid = cr.pid;
+ }
+ return ret;
+}