[DRBD-cvs] svn commit by phil - r2204 - trunk/user - Christopher Boumenot's patch that removes some calls to

drbd-cvs at lists.linbit.com drbd-cvs at lists.linbit.com
Mon May 22 13:27:58 CEST 2006


Author: phil
Date: 2006-05-22 13:27:56 +0200 (Mon, 22 May 2006)
New Revision: 2204

Modified:
   trunk/user/drbdadm.h
   trunk/user/drbdadm_main.c
Log:
Christopher Boumenot's patch that removes some calls to external
programs to verify user supplied IP addresses.


Modified: trunk/user/drbdadm.h
===================================================================
--- trunk/user/drbdadm.h	2006-05-18 15:07:08 UTC (rev 2203)
+++ trunk/user/drbdadm.h	2006-05-22 11:27:56 UTC (rev 2204)
@@ -4,6 +4,8 @@
 #include <linux/drbd_config.h>
 #include <sys/utsname.h>
 #include <sys/types.h>
+#include <net/if.h>
+#include <stdint.h>
 
 #define E_syntax	  2
 #define E_usage		  3
@@ -48,6 +50,19 @@
   enum usage_count_type usage_count;
 };
 
+#define IFI_HADDR 8
+#define IFI_ALIAS 1
+
+struct ifi_info {
+  char ifi_name[IFNAMSIZ];      /* interface name, nul terminated */
+  uint8_t ifi_haddr[IFI_HADDR]; /* hardware address */
+  uint16_t ifi_hlen;            /* bytes in hardware address, 0, 6, 8 */
+  short ifi_flags;              /* IFF_xxx constants from <net/if.h> */
+  short ifi_myflags;            /* our own IFI_xxx flags */
+  struct sockaddr *ifi_addr;    /* primary address */
+  struct ifi_info *ifi_next;    /* next ifi_info structure */
+};
+
 struct d_host_info
 {
   char* name;

Modified: trunk/user/drbdadm_main.c
===================================================================
--- trunk/user/drbdadm_main.c	2006-05-18 15:07:08 UTC (rev 2203)
+++ trunk/user/drbdadm_main.c	2006-05-22 11:27:56 UTC (rev 2204)
@@ -37,6 +37,10 @@
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <sys/poll.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <errno.h>
@@ -103,6 +107,8 @@
 static int adm_generic_b(struct d_resource* ,const char* );
 static int hidden_cmds(struct d_resource* ,const char* );
 
+static struct ifi_info* get_ifi_info(int family);
+
 char ss_buffer[255];
 struct utsname nodeinfo;
 int line=1;
@@ -1153,87 +1159,162 @@
   exit(E_usage);
 }
 
-/* if not verifyable, prints a message to stderr,
- * and sets config_valid = 0 if INVALID_IP_IS_INVALID_CONF is defined */
-#define INVALID_IP_IS_INVALID_CONF 0
-void verify_ips(struct d_resource* res)
+static void free_ifi_info(struct ifi_info *ifihead)
 {
-  char *my_ip = NULL;
-  char *his_ip = NULL;
-  char *argv[] = { "/bin/bash", "-c", NULL, "drbdadm:verify_ips", NULL };
-  int ex;
+  struct ifi_info *ifi, *ifinext;
+  for (ifi = ifihead; ifi != NULL; ifi = ifinext) {
+    if (ifi->ifi_addr != NULL)
+      free(ifi->ifi_addr);
+    ifinext = ifi->ifi_next;
+    free(ifi);
+  }
+}
 
-  if (global_options.disable_ip_verification) return;
-  if (dry_run == 1 || do_verify_ips == 0) return;
+static struct ifi_info* get_ifi_info(int family)
+{
+  struct ifi_info *ifi, *ifihead, **ifipnext;
+  int sockfd, len, lastlen, flags, myflags;
+  char *ptr, *buf, lastname[IFNAMSIZ], *cptr;
+  struct ifconf ifc;
+  struct ifreq *ifr, ifrcopy;
+  struct sockaddr_in *sinptr;
+    
+  sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+  if (sockfd < 0) {
+    fprintf(stderr, "sockfd < 0\n");
+    return NULL;
+  }
 
-  if (!(res && res->me   && res->me->address
-	    && res->peer && res->peer->address)) {
-    fprintf(stderr, "OOPS, no resource info in verify_ips!\n");
-    exit(E_config_invalid);
+  lastlen = 0;
+  len = 100 * sizeof(struct ifreq); /* initial guess */
+    
+  for (;;) {
+    buf = malloc(len);
+    if (!buf)
+      return NULL;
+    ifc.ifc_len = len;
+    ifc.ifc_buf = buf;
+        
+    if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
+      if (errno != EINVAL || lastlen != 0)
+	return NULL;
+    } else {
+      if (ifc.ifc_len == lastlen)
+	break; /* success, len has not changed */
+      lastlen = ifc.ifc_len;
+    }
+    len += 10 * sizeof(struct ifreq); /* increment */
+    free(buf);
   }
-  my_ip  = res->me->address;
-  his_ip = res->peer->address;
 
-  ex = asprintf(&argv[2],
-	"IP=%s; IP=${IP//./\\\\.};"
-	"LANG=; PATH=/sbin/:$PATH;"
-	"if   type -p ip       ; then"
-	"  ip addr show | grep -qE 'inet '$IP'[ /]';"
-	"elif type -p ifconfig ; then"
-	"  ifconfig | grep -qE ' inet addr:'$IP' ';"
-	"else"
-	"  echo >&2 $0: 'neither ip nor ifconfig found!';"
-	"fi >/dev/null",
-	my_ip);
-  if (ex < 0) { perror("asprintf"); exit(E_thinko); }
-  ex = m_system(argv,SLEEPS_SHORT|DONT_REPORT_FAILED);
-  free(argv[2]); argv[2] = NULL;
+  ifihead = NULL;
+  ifipnext = &ifihead;
+  lastname[0] = 0;
 
-  if (ex != 0) {
-    ENTRY e, *ep;
-    e.key = e.data = ep = NULL;
-    asprintf(&e.key,"%s:%s",my_ip,res->me->port);
-    ep = hsearch(e, FIND);
-    fprintf(stderr, "%s:%d: in resource %s, on %s:\n\t"
-		    "IP %s not found on this host.\n",
-	    config_file,(int)(long)ep->data,res->name, res->me->name,my_ip);
-    if (INVALID_IP_IS_INVALID_CONF)
-	    config_valid = 0;
-    free(e.key);
-    return;
+  for (ptr = buf; ptr < buf + ifc.ifc_len; ) {
+    ifr = (struct ifreq*) ptr;
+
+    switch (ifr->ifr_addr.sa_family) {
+      /*         case AF_INET6: len = sizeof(struct sockaddr_in6); break; */
+    case AF_INET:
+    default:
+      len = sizeof(struct sockaddr);
+      break;
+    }
+        
+    ptr += sizeof(ifr->ifr_name) + len; /* for next one in buffer */
+        
+    if (ifr->ifr_addr.sa_family != family)
+      continue; /* ignore if not desired address family */
+        
+    myflags = 0;
+    if ((cptr = strchr(ifr->ifr_name, ':')) != NULL)
+      *cptr = 0; /* replace colon with null */
+
+    if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0)
+      myflags = IFI_ALIAS;
+
+    memcpy(lastname, ifr->ifr_name, IFNAMSIZ);
+
+    ifrcopy = *ifr;
+    if (ioctl(sockfd, SIOCGIFFLAGS, &ifrcopy) < 0)
+      return NULL;
+
+    flags = ifrcopy.ifr_flags;
+    if ((flags & IFF_UP) == 0)
+      continue; /* ignore if the interface is not up */
+
+    ifi = calloc(1, sizeof(struct ifi_info));
+    if (!ifi)
+      return NULL;
+        
+    *ifipnext = ifi; /* prev points to this new one */
+    ifipnext = &ifi->ifi_next; /* pointer to next one goes here */
+
+    ifi->ifi_flags = flags; /* IFI_xxx values */
+    ifi->ifi_myflags = myflags; /* IFI_xxx values */
+    memcpy(ifi->ifi_name, ifr->ifr_name, IFNAMSIZ);
+    ifi->ifi_name[IFNAMSIZ - 1] = '\0';
+
+    switch(ifr->ifr_addr.sa_family) {
+      /*         case AF_INET6: return NULL; */
+    case AF_INET:
+      sinptr = (struct sockaddr_in *)&ifr->ifr_addr;
+      if (ifi->ifi_addr == NULL) {
+	ifi->ifi_addr = calloc(1, sizeof(struct sockaddr));
+	if (!ifi->ifi_addr)
+	  return NULL;
+
+	memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr));
+      }
+      /* IFF_BROADCAST and IFF_POINTTOPOINT are ignored */
+    default:
+      break;
+    }
   }
 
-#if 1
-/* seems to not work as expected with aliases.
- * maybe drop it completely and trust the admin.
- */
-  ex = asprintf(&argv[2],
-	"IP=%s; IPQ=${IP//./\\\\.};"
-	"peerIP=%s; peerIPQ=${peerIP//./\\\\.};"
-	"LANG=; PATH=/sbin/:$PATH;"
-	"if type -p ip ; then "
-	"  ip -o route get to $peerIP from $IP 2>/dev/null |"
-	"    grep -qE ^$peerIPQ' from '$IPQ' ';"
-	/* "else"
-	 * "  echo >&2 $0: 'cannot check route to peer';" */
-	"fi >/dev/null",
-	my_ip,his_ip);
-  if (ex < 0) { perror("asprintf"); exit(E_thinko); }
-  ex = m_system(argv,SLEEPS_SHORT);
-  free(argv[2]); argv[2] = NULL;
-  if (ex != 0) {
-    ENTRY e, *ep;
-    e.key = e.data = ep = NULL;
-    asprintf(&e.key,"%s:%s",his_ip,res->peer->port);
-    ep = hsearch(e, FIND);
-    fprintf(stderr, "%s:%d: in resource %s:\n\tNo route from me (%s) to peer (%s).\n",
-	    config_file,(int)(long)ep->data,res->name, my_ip, his_ip);
-    if (INVALID_IP_IS_INVALID_CONF)
-	    config_valid = 0;
-    return;
+  free(buf);
+  close(sockfd);
+
+  return ifihead;
+}
+
+void verify_ips(struct d_resource* res)
+{
+  struct ifi_info *ifi, *ifihead;
+  int family, valid = 0;
+  uint32_t addr = 0;
+  struct in_addr sin_addr;
+  const char *my_ip;
+
+  my_ip = res->me->address;
+
+  /* does DRBD support inet6? */
+  family = AF_INET;
+    
+  for (ifihead = ifi = get_ifi_info(family); ifi != NULL; ifi = ifi->ifi_next) {        
+    switch (family) {
+    case AF_INET: {
+      struct sockaddr_in * sin = (struct sockaddr_in *)ifi->ifi_addr;
+      addr = sin->sin_addr.s_addr;
+
+      if (addr == sin_addr.s_addr) /* loop a few times needlessly */
+	valid = 1;
+      break;
+    }
+    default:
+      break;
+    }
   }
+
+  free_ifi_info(ifihead);
+
+  if (valid == 0) {
+    fprintf(stderr, "OOPS, the IP address %s isn't configure/up on your system!\n", my_ip);
+#ifdef INVALID_IP_IS_INVALID_CONF
+    config_valid = 0;
 #endif
-
+  }
   return;
 }
 



More information about the drbd-cvs mailing list