Index: user/drbdadm_main.c =================================================================== --- user/drbdadm_main.c (revision 2198) +++ user/drbdadm_main.c (working copy) @@ -38,12 +38,16 @@ #include #include #include +#include +#include +#include #include #include #include #include #include #include +#include #include "drbdadm.h" @@ -99,6 +103,8 @@ static int sh_ll_dev(struct d_resource* ,char* ); static int sh_md_dev(struct d_resource* ,char* ); static int sh_md_idx(struct d_resource* ,char* ); +static struct ifi_info* get_ifi_info(int family); +static int verify_ips(const char *my_ip); char ss_buffer[255]; struct utsname nodeinfo; @@ -461,8 +467,8 @@ case SLEEPS_LONG: timeout = 120; break; case SLEEPS_VERY_LONG: timeout = 600; break; default: - fprintf(stderr,"%s:%u: oops... flags=%02x\n", __FILE__ , __LINE__ , flags); - exit(E_thinko); + fprintf(stderr,"%s:%u: oops... flags=%02x\n", __FILE__ , __LINE__ , flags); + exit(E_thinko); } alarm(timeout); } @@ -475,7 +481,7 @@ if (waitpid(pid, &status, 0) == -1) { if (errno != EINTR) break; if (alarm_raised) { - fprintf(stderr,"Child process does not terminate!\nExiting.\n"); + fprintf(stderr,"Child process does not terminate!\nExiting.\n"); exit(E_exec_error); } else { fprintf(stderr,"logic bug in %s:%d\n",__FILE__,__LINE__); @@ -992,89 +998,179 @@ exit(E_usage); } +static void free_ifi_info(struct ifi_info *ifihead) +{ + 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); + } +} + +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; + } + + 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); + } + + ifihead = NULL; + ifipnext = &ifihead; + lastname[0] = 0; + + 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; + } + } + + free(buf); + close(sockfd); + + return ifihead; +} + +static int verify_ips(const char *my_ip) +{ + struct ifi_info *ifi, *ifihead; + int family, valid = 0; + uint32_t addr = 0; + struct in_addr sin_addr; + + /* 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 (inet_aton(my_ip, &sin_addr) < 0) /* can this happen? */ + return -1; + + 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 0; +} + /* if not verifyable, prints a message to stderr, * and sets config_valid = 0 if INVALID_IP_IS_INVALID_CONF is defined */ -void verify_ips(struct d_resource* res) +void verify_network(struct d_resource* res) { - char *my_ip = NULL; - char *his_ip = NULL; - char *argv[] = { "/bin/bash", "-c", NULL, "drbdadm:verify_ips", NULL }; - int ex; - if (global_options.disable_ip_verification) return; - if (dry_run == 1 || do_verify_ips == 0) return; +/* if (dry_run == 1 || do_verify_ips == 0) return; */ 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); } - 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; - - 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); -#ifdef INVALID_IP_IS_INVALID_CONF - config_valid = 0; -#endif - free(e.key); - return; - } - -#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); -# ifdef INVALID_IP_IS_INVALID_CONF - config_valid = 0; -# endif - return; - } -#endif - - return; + verify_ips(res->me->address); } static char* conf_file[] = { @@ -1159,7 +1255,7 @@ config_valid = 0; } if (res->me && res->peer) - verify_ips(res); + verify_network(res); } Index: user/drbdadm.h =================================================================== --- user/drbdadm.h (revision 2198) +++ user/drbdadm.h (working copy) @@ -4,6 +4,8 @@ #include #include #include +#include +#include #define E_syntax 2 #define E_usage 3 @@ -30,7 +32,6 @@ /* for verify_ips(): make not verifyable ips fatal */ //#define INVALID_IP_IS_INVALID_CONF - struct d_globals { int disable_io_hints; @@ -72,6 +73,19 @@ struct d_resource* next; }; +#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 */ + short ifi_myflags; /* our own IFI_xxx flags */ + struct sockaddr *ifi_addr; /* primary address */ + struct ifi_info *ifi_next; /* next ifi_info structure */ +}; + extern int adm_attach(struct d_resource* ,char* ); extern int adm_connect(struct d_resource* ,char* ); extern int adm_resize(struct d_resource* ,char* ); @@ -80,7 +94,7 @@ extern struct d_option* find_opt(struct d_option*,char*); extern void validate_resource(struct d_resource *); extern int check_uniq(const char* what, const char *fmt, ...); -extern void verify_ips(struct d_resource* res); +extern void verify_network(struct d_resource* res); extern void schedule_dcmd( int (* function)(struct d_resource*,char* ), struct d_resource* res, int order);