mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	* ext/socket: Bypass getaddrinfo() if node and serv are numeric.
Reporeted by Naotoshi Seo. [ruby-core:60801] [Bug #9525] * ext/socket/extconf.rb: Detect struct sockaddr_in6.sin6_len. * ext/socket/sockport.h (SET_SIN6_LEN): New macro. (INIT_SOCKADDR_IN6): Ditto. * ext/socket/rubysocket.h (struct rb_addrinfo): Add allocated_by_malloc field. * ext/socket/raddrinfo.c (numeric_getaddrinfo): New function. (rb_getaddrinfo): Call numeric_getaddrinfo at first. (rb_freeaddrinfo): Free struct addrinfo properly when it is allocated by numeric_getaddrinfo. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@45047 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
		
							parent
							
								
									dd1c3a7509
								
							
						
					
					
						commit
						2e6b97a45d
					
				
					 5 changed files with 146 additions and 9 deletions
				
			
		
							
								
								
									
										18
									
								
								ChangeLog
									
										
									
									
									
								
							
							
						
						
									
										18
									
								
								ChangeLog
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1,3 +1,21 @@
 | 
			
		|||
Wed Feb 19 18:57:02 2014  Tanaka Akira  <akr@fsij.org>
 | 
			
		||||
 | 
			
		||||
	* ext/socket: Bypass getaddrinfo() if node and serv are numeric.
 | 
			
		||||
	  Reporeted by Naotoshi Seo.  [ruby-core:60801] [Bug #9525]
 | 
			
		||||
 | 
			
		||||
	* ext/socket/extconf.rb: Detect struct sockaddr_in6.sin6_len.
 | 
			
		||||
 | 
			
		||||
	* ext/socket/sockport.h (SET_SIN6_LEN): New macro.
 | 
			
		||||
	  (INIT_SOCKADDR_IN6): Ditto.
 | 
			
		||||
 | 
			
		||||
	* ext/socket/rubysocket.h (struct rb_addrinfo): Add
 | 
			
		||||
	  allocated_by_malloc field.
 | 
			
		||||
 | 
			
		||||
	* ext/socket/raddrinfo.c (numeric_getaddrinfo): New function.
 | 
			
		||||
	  (rb_getaddrinfo): Call numeric_getaddrinfo at first.
 | 
			
		||||
	  (rb_freeaddrinfo): Free struct addrinfo properly when it is
 | 
			
		||||
	  allocated by numeric_getaddrinfo.
 | 
			
		||||
 | 
			
		||||
Wed Feb 19 18:31:48 2014  Tanaka Akira  <akr@fsij.org>
 | 
			
		||||
 | 
			
		||||
	* ext/socket: Wrap struct addrinfo by struct rb_addrinfo.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -332,6 +332,7 @@ end
 | 
			
		|||
 | 
			
		||||
have_struct_member("struct sockaddr", "sa_len", headers) # 4.4BSD
 | 
			
		||||
have_struct_member("struct sockaddr_in", "sin_len", headers) # 4.4BSD
 | 
			
		||||
have_struct_member("struct sockaddr_in6", "sin6_len", headers) # 4.4BSD
 | 
			
		||||
 | 
			
		||||
if have_type("struct sockaddr_un", headers) # POSIX
 | 
			
		||||
  have_struct_member("struct sockaddr_un", "sun_len", headers) # 4.4BSD
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -171,6 +171,90 @@ nogvl_getaddrinfo(void *arg)
 | 
			
		|||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
numeric_getaddrinfo(const char *node, const char *service,
 | 
			
		||||
        const struct addrinfo *hints,
 | 
			
		||||
        struct addrinfo **res)
 | 
			
		||||
{
 | 
			
		||||
    static const struct {
 | 
			
		||||
        int socktype;
 | 
			
		||||
        int protocol;
 | 
			
		||||
    } list[] = {
 | 
			
		||||
        { SOCK_STREAM, IPPROTO_TCP },
 | 
			
		||||
        { SOCK_DGRAM, IPPROTO_UDP },
 | 
			
		||||
        { SOCK_RAW, 0 }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct addrinfo *ai = NULL;
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_INET_PTON
 | 
			
		||||
    if (node && (!service || strspn(service, "0123456789") == strlen(service))) {
 | 
			
		||||
        int port = service ? (unsigned short)atoi(service): 0;
 | 
			
		||||
        int hint_family = hints ? hints->ai_family : PF_UNSPEC;
 | 
			
		||||
        int hint_socktype = hints ? hints->ai_socktype : 0;
 | 
			
		||||
        int hint_protocol = hints ? hints->ai_protocol : 0;
 | 
			
		||||
        char ipv4addr[4];
 | 
			
		||||
#ifdef AF_INET6
 | 
			
		||||
        char ipv6addr[16];
 | 
			
		||||
        if ((hint_family == PF_UNSPEC || hint_family == PF_INET6) &&
 | 
			
		||||
            strspn(node, "0123456789abcdefABCDEF.:") == strlen(node) &&
 | 
			
		||||
            inet_pton(AF_INET6, node, ipv6addr)) {
 | 
			
		||||
            int i;
 | 
			
		||||
            for (i = numberof(list)-1; 0 <= i; i--) {
 | 
			
		||||
                if ((hint_socktype == 0 || hint_socktype == list[i].socktype) &&
 | 
			
		||||
                    (hint_protocol == 0 || list[i].protocol == 0 || hint_protocol == list[i].protocol)) {
 | 
			
		||||
                    struct addrinfo *ai0 = xmalloc(sizeof(struct addrinfo));
 | 
			
		||||
                    struct sockaddr_in6 *sa = xmalloc(sizeof(struct sockaddr_in6));
 | 
			
		||||
                    MEMZERO(ai0, sizeof(struct addrinfo), 1);
 | 
			
		||||
                    INIT_SOCKADDR_IN6(sa, sizeof(struct sockaddr_in6));
 | 
			
		||||
                    memcpy(&sa->sin6_addr, ipv6addr, sizeof(ipv6addr));
 | 
			
		||||
                    sa->sin6_port = htons(port);
 | 
			
		||||
                    ai0->ai_family = PF_INET6;
 | 
			
		||||
                    ai0->ai_socktype = list[i].socktype;
 | 
			
		||||
                    ai0->ai_protocol = hint_protocol ? hint_protocol : list[i].protocol;
 | 
			
		||||
                    ai0->ai_addrlen = sizeof(struct sockaddr_in6);
 | 
			
		||||
                    ai0->ai_addr = (struct sockaddr *)sa;
 | 
			
		||||
                    ai0->ai_canonname = NULL;
 | 
			
		||||
                    ai0->ai_next = ai;
 | 
			
		||||
                    ai = ai0;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
#endif
 | 
			
		||||
        if ((hint_family == PF_UNSPEC || hint_family == PF_INET) &&
 | 
			
		||||
            strspn(node, "0123456789.") == strlen(node) &&
 | 
			
		||||
            inet_pton(AF_INET, node, ipv4addr)) {
 | 
			
		||||
            int i;
 | 
			
		||||
            for (i = numberof(list)-1; 0 <= i; i--) {
 | 
			
		||||
                if ((hint_socktype == 0 || hint_socktype == list[i].socktype) &&
 | 
			
		||||
                    (hint_protocol == 0 || list[i].protocol == 0 || hint_protocol == list[i].protocol)) {
 | 
			
		||||
                    struct addrinfo *ai0 = xmalloc(sizeof(struct addrinfo));
 | 
			
		||||
                    struct sockaddr_in *sa = xmalloc(sizeof(struct sockaddr_in));
 | 
			
		||||
                    MEMZERO(ai0, sizeof(struct addrinfo), 1);
 | 
			
		||||
                    INIT_SOCKADDR_IN(sa, sizeof(struct sockaddr_in));
 | 
			
		||||
                    memcpy(&sa->sin_addr, ipv4addr, sizeof(ipv4addr));
 | 
			
		||||
                    sa->sin_port = htons(port);
 | 
			
		||||
                    ai0->ai_family = PF_INET;
 | 
			
		||||
                    ai0->ai_socktype = list[i].socktype;
 | 
			
		||||
                    ai0->ai_protocol = hint_protocol ? hint_protocol : list[i].protocol;
 | 
			
		||||
                    ai0->ai_addrlen = sizeof(struct sockaddr_in);
 | 
			
		||||
                    ai0->ai_addr = (struct sockaddr *)sa;
 | 
			
		||||
                    ai0->ai_canonname = NULL;
 | 
			
		||||
                    ai0->ai_next = ai;
 | 
			
		||||
                    ai = ai0;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (ai) {
 | 
			
		||||
            *res = ai;
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
    return EAI_FAIL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
rb_getaddrinfo(const char *node, const char *service,
 | 
			
		||||
               const struct addrinfo *hints,
 | 
			
		||||
| 
						 | 
				
			
			@ -178,21 +262,28 @@ rb_getaddrinfo(const char *node, const char *service,
 | 
			
		|||
{
 | 
			
		||||
    struct addrinfo *ai;
 | 
			
		||||
    int ret;
 | 
			
		||||
    int allocated_by_malloc = 0;
 | 
			
		||||
 | 
			
		||||
    ret = numeric_getaddrinfo(node, service, hints, &ai);
 | 
			
		||||
    if (ret == 0)
 | 
			
		||||
        allocated_by_malloc = 1;
 | 
			
		||||
    else {
 | 
			
		||||
#ifdef GETADDRINFO_EMU
 | 
			
		||||
    ret = getaddrinfo(node, service, hints, &ai);
 | 
			
		||||
        ret = getaddrinfo(node, service, hints, &ai);
 | 
			
		||||
#else
 | 
			
		||||
    struct getaddrinfo_arg arg;
 | 
			
		||||
    MEMZERO(&arg, sizeof arg, 1);
 | 
			
		||||
    arg.node = node;
 | 
			
		||||
    arg.service = service;
 | 
			
		||||
    arg.hints = hints;
 | 
			
		||||
    arg.res = &ai;
 | 
			
		||||
    ret = (int)(VALUE)rb_thread_call_without_gvl(nogvl_getaddrinfo, &arg, RUBY_UBF_IO, 0);
 | 
			
		||||
        struct getaddrinfo_arg arg;
 | 
			
		||||
        MEMZERO(&arg, sizeof arg, 1);
 | 
			
		||||
        arg.node = node;
 | 
			
		||||
        arg.service = service;
 | 
			
		||||
        arg.hints = hints;
 | 
			
		||||
        arg.res = &ai;
 | 
			
		||||
        ret = (int)(VALUE)rb_thread_call_without_gvl(nogvl_getaddrinfo, &arg, RUBY_UBF_IO, 0);
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (ret == 0) {
 | 
			
		||||
        *res = (struct rb_addrinfo *)xmalloc(sizeof(struct rb_addrinfo));
 | 
			
		||||
        (*res)->allocated_by_malloc = allocated_by_malloc;
 | 
			
		||||
        (*res)->ai = ai;
 | 
			
		||||
    }
 | 
			
		||||
    return ret;
 | 
			
		||||
| 
						 | 
				
			
			@ -201,7 +292,18 @@ rb_getaddrinfo(const char *node, const char *service,
 | 
			
		|||
void
 | 
			
		||||
rb_freeaddrinfo(struct rb_addrinfo *ai)
 | 
			
		||||
{
 | 
			
		||||
    freeaddrinfo(ai->ai);
 | 
			
		||||
    if (!ai->allocated_by_malloc)
 | 
			
		||||
        freeaddrinfo(ai->ai);
 | 
			
		||||
    else {
 | 
			
		||||
        struct addrinfo *ai1, *ai2;
 | 
			
		||||
        ai1 = ai->ai;
 | 
			
		||||
        while (ai1) {
 | 
			
		||||
            ai2 = ai1->ai_next;
 | 
			
		||||
            xfree(ai1->ai_addr);
 | 
			
		||||
            xfree(ai1);
 | 
			
		||||
            ai1 = ai2;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    xfree(ai);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -280,6 +280,7 @@ int rsock_getfamily(int sockfd);
 | 
			
		|||
 | 
			
		||||
struct rb_addrinfo {
 | 
			
		||||
  struct addrinfo *ai;
 | 
			
		||||
  int allocated_by_malloc;
 | 
			
		||||
};
 | 
			
		||||
int rb_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct rb_addrinfo **res);
 | 
			
		||||
void rb_freeaddrinfo(struct rb_addrinfo *ai);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,6 +29,12 @@
 | 
			
		|||
# define SET_SIN_LEN(sa, len) SET_SA_LEN((struct sockaddr *)(sa), (len))
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN
 | 
			
		||||
# define SET_SIN6_LEN(sa, len) (void)((sa)->sin6_len = (len))
 | 
			
		||||
#else
 | 
			
		||||
# define SET_SIN6_LEN(sa, len) SET_SA_LEN((struct sockaddr *)(sa), (len))
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define INIT_SOCKADDR(addr, family, len) \
 | 
			
		||||
  do { \
 | 
			
		||||
    struct sockaddr *init_sockaddr_ptr = (addr); \
 | 
			
		||||
| 
						 | 
				
			
			@ -47,6 +53,15 @@
 | 
			
		|||
    SET_SIN_LEN(init_sockaddr_ptr, init_sockaddr_len); \
 | 
			
		||||
  } while (0)
 | 
			
		||||
 | 
			
		||||
#define INIT_SOCKADDR_IN6(addr, len) \
 | 
			
		||||
  do { \
 | 
			
		||||
    struct sockaddr_in6 *init_sockaddr_ptr = (addr); \
 | 
			
		||||
    socklen_t init_sockaddr_len = (len); \
 | 
			
		||||
    memset(init_sockaddr_ptr, 0, init_sockaddr_len); \
 | 
			
		||||
    init_sockaddr_ptr->sin6_family = AF_INET6; \
 | 
			
		||||
    SET_SIN6_LEN(init_sockaddr_ptr, init_sockaddr_len); \
 | 
			
		||||
  } while (0)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* for strict-aliasing rule */
 | 
			
		||||
#ifdef HAVE_TYPE_STRUCT_SOCKADDR_UN
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue