core: added a few variants for parsing IPv4/6 addresses
authorDaniel-Constantin Mierla <miconda@gmail.com>
Wed, 22 May 2019 10:26:09 +0000 (12:26 +0200)
committerDaniel-Constantin Mierla <miconda@gmail.com>
Wed, 22 May 2019 10:28:11 +0000 (12:28 +0200)
- store parsed structure directly in a provided buffer
- wrapper for parsing either IPv4 or IPv6

src/core/resolve.c
src/core/resolve.h

index 2c43715..5169c85 100644 (file)
@@ -1254,7 +1254,7 @@ struct hostent* srv_sip_resolvehost(str* name, int zt, unsigned short* port,
                                                                                                                  don't find another */
                /* check if it's an ip address */
                if (((ip=str2ip(name))!=0)
-                         || ((ip=str2ip6(name))!=0) 
+                         || ((ip=str2ip6(name))!=0)
                         ){
                        /* we are lucky, this is an ip address */
                        he=ip_addr2he(name, ip);
@@ -1264,7 +1264,7 @@ struct hostent* srv_sip_resolvehost(str* name, int zt, unsigned short* port,
                        LM_WARN("domain name too long (%d), unable to perform SRV lookup\n",
                                                name->len);
                }else{
-                       
+
                        switch(srv_proto){
                                case PROTO_UDP:
                                case PROTO_TCP:
@@ -1691,7 +1691,7 @@ int sip_hostport2su(union sockaddr_union* su, str* name, unsigned short port,
                                                char* proto)
 {
        struct hostent* he;
-       
+
        he=sip_resolvehost(name, &port, proto);
        if (he==0){
                ser_error=E_BAD_ADDRESS;
@@ -1708,3 +1708,209 @@ int sip_hostport2su(union sockaddr_union* su, str* name, unsigned short port,
 error:
        return -1;
 }
+
+/* converts a str to an ipv4 address struct stored in ipb
+ * - ipb must be already allocated
+ * - return 0 on success; <0 on failure */
+int str2ipbuf(str* st, ip_addr_t* ipb)
+{
+       int i;
+       unsigned char *limit;
+       unsigned char* s;
+
+       /* just in case that e.g. the VIA parser get confused */
+       if(unlikely(!st->s || st->len <= 0)) {
+               LM_ERR("invalid name, no conversion to IP address possible\n");
+               return 0;
+       }
+       s=(unsigned char*)st->s;
+
+       /*init*/
+       ipb->u.addr32[0]=0;
+       i=0;
+       limit=(unsigned char*)(st->s + st->len);
+
+       for(;s<limit ;s++){
+               if (*s=='.'){
+                               i++;
+                               if (i>3) goto error_dots;
+               }else if ( (*s <= '9' ) && (*s >= '0') ){
+                               ipb->u.addr[i]=ipb->u.addr[i]*10+*s-'0';
+               }else{
+                               //error unknown char
+                               goto error_char;
+               }
+       }
+       if (i<3) goto error_dots;
+       ipb->af=AF_INET;
+       ipb->len=4;
+
+       return 0;
+
+error_dots:
+       DBG("error - too %s dots in [%.*s]\n", (i>3)?"many":"few",
+                       st->len, st->s);
+       return -1;
+ error_char:
+       /*
+       DBG("warning - unexpected char %c in [%.*s]\n", *s, st->len, st->s);
+       */
+       return -2;
+}
+
+/* converts a str to an ipv4 address, returns the address or 0 on error
+   Warning: the result is a pointer to a statically allocated structure */
+ip_addr_t* str2ip(str* st)
+{
+       static ip_addr_t ip;
+
+       if(str2ipbuf(st, &ip)<0) {
+               return NULL;
+       }
+
+       return &ip;
+}
+
+/* converts a str to an ipv6 address struct stored in ipb
+ * - ipb must be already allocated
+ * - return 0 on success; <0 on failure */
+int str2ip6buf(str* st, ip_addr_t* ipb)
+{
+       int i, idx1, rest;
+       int no_colons;
+       int double_colon;
+       int hex;
+       unsigned short* addr_start;
+       unsigned short addr_end[8];
+       unsigned short* addr;
+       unsigned char* limit;
+       unsigned char* s;
+
+       /* just in case that e.g. the VIA parser get confused */
+       if(unlikely(!st->s || st->len <= 0)) {
+               LM_ERR("invalid name, no conversion to IP address possible\n");
+               return -1;
+       }
+       /* init */
+       if ((st->len) && (st->s[0]=='[')){
+               /* skip over [ ] */
+               if (st->s[st->len-1]!=']') goto error_char;
+               s=(unsigned char*)(st->s+1);
+               limit=(unsigned char*)(st->s+st->len-1);
+       }else{
+               s=(unsigned char*)st->s;
+               limit=(unsigned char*)(st->s+st->len);
+       }
+       i=idx1=rest=0;
+       double_colon=0;
+       no_colons=0;
+       ipb->af=AF_INET6;
+       ipb->len=16;
+       addr_start=ipb->u.addr16;
+       addr=addr_start;
+       memset(addr_start, 0 , 8*sizeof(unsigned short));
+       memset(addr_end, 0 , 8*sizeof(unsigned short));
+       for (; s<limit; s++){
+               if (*s==':'){
+                       no_colons++;
+                       if (no_colons>7) goto error_too_many_colons;
+                       if (double_colon){
+                               idx1=i;
+                               i=0;
+                               if (addr==addr_end) goto error_colons;
+                               addr=addr_end;
+                       }else{
+                               double_colon=1;
+                               addr[i]=htons(addr[i]);
+                               i++;
+                       }
+               }else if ((hex=HEX2I(*s))>=0){
+                               addr[i]=addr[i]*16+hex;
+                               double_colon=0;
+               }else{
+                       /* error, unknown char */
+                       goto error_char;
+               }
+       }
+       if (!double_colon){ /* not ending in ':' */
+               addr[i]=htons(addr[i]);
+               i++;
+       }
+       /* if address contained '::' fix it */
+       if (addr==addr_end){
+               rest=8-i-idx1;
+               memcpy(addr_start+idx1+rest, addr_end, i*sizeof(unsigned short));
+       }else{
+               /* no double colons inside */
+               if (no_colons<7) goto error_too_few_colons;
+       }
+/*
+       DBG("idx1=%d, rest=%d, no_colons=%d, hex=%x\n",
+                       idx1, rest, no_colons, hex);
+       DBG("address %x:%x:%x:%x:%x:%x:%x:%x\n",
+                       addr_start[0], addr_start[1], addr_start[2],
+                       addr_start[3], addr_start[4], addr_start[5],
+                       addr_start[6], addr_start[7] );
+*/
+       return 0;
+
+error_too_many_colons:
+       DBG("error - too many colons in [%.*s]\n", st->len, st->s);
+       return -1;
+
+error_too_few_colons:
+       DBG("error - too few colons in [%.*s]\n", st->len, st->s);
+       return -2;
+
+error_colons:
+       DBG("error - too many double colons in [%.*s]\n", st->len, st->s);
+       return -3;
+
+error_char:
+       /*
+       DBG("warning - unexpected char %c in  [%.*s]\n", *s, st->len,
+                       st->s);*/
+       return -4;
+}
+
+/* returns an ip_addr struct.; on error returns 0
+ * the ip_addr struct is static, so subsequent calls will destroy its content*/
+ip_addr_t* str2ip6(str* st)
+{
+       static ip_addr_t ip;
+
+       if(str2ip6buf(st, &ip)<0) {
+               return NULL;
+       }
+
+       return &ip;
+}
+
+/* converts a str to an ipvv/6 address struct stored in ipb
+ * - ipb must be already allocated
+ * - return 0 on success; <0 on failure */
+int str2ipxbuf(str* st, ip_addr_t* ipb)
+{
+       if (str2ipbuf(st, ipb)<0) {
+               if(str2ip6buf(st, ipb) < 0) {
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+/* returns an ip_addr struct converted from ipv4/6 str; on error returns 0
+ * the ip_addr struct is static, so subsequent calls will destroy its content*/
+struct ip_addr* str2ipx(str* st)
+{
+       static ip_addr_t ip;
+
+       if(str2ipbuf(st, &ip)<0) {
+               if(str2ip6buf(st, &ip)<0) {
+                       return NULL;
+               }
+       }
+
+       return &ip;
+}
index 0c4949a..5ef849c 100644 (file)
@@ -212,161 +212,12 @@ void free_rdata_list(struct rdata* head);
                (((c)>='a') && ((c)<='f'))? ((c)-'a')+10 : -1 )
 
 
-
-
-
-/* converts a str to an ipv4 address, returns the address or 0 on error
-   Warning: the result is a pointer to a statically allocated structure */
-static inline struct ip_addr* str2ip(str* st)
-{
-       int i;
-       unsigned char *limit;
-       static struct ip_addr ip;
-       unsigned char* s;
-
-       /* just in case that e.g. the VIA parser get confused */
-       if(unlikely(!st->s || st->len <= 0)) {
-               LM_ERR("invalid name, no conversion to IP address possible\n");
-               return 0;
-       }
-       s=(unsigned char*)st->s;
-
-       /*init*/
-       ip.u.addr32[0]=0;
-       i=0;
-       limit=(unsigned char*)(st->s + st->len);
-
-       for(;s<limit ;s++){
-               if (*s=='.'){
-                               i++;
-                               if (i>3) goto error_dots;
-               }else if ( (*s <= '9' ) && (*s >= '0') ){
-                               ip.u.addr[i]=ip.u.addr[i]*10+*s-'0';
-               }else{
-                               //error unknown char
-                               goto error_char;
-               }
-       }
-       if (i<3) goto error_dots;
-       ip.af=AF_INET;
-       ip.len=4;
-       
-       return &ip;
-error_dots:
-       DBG("str2ip: ERROR: too %s dots in [%.*s]\n", (i>3)?"many":"few", 
-                       st->len, st->s);
-       return 0;
- error_char:
-       /*
-       DBG("str2ip: WARNING: unexpected char %c in [%.*s]\n", *s, st->len, st->s);
-       */
-       return 0;
-}
-
-
-/* returns an ip_addr struct.; on error returns 0
- * the ip_addr struct is static, so subsequent calls will destroy its content*/
-static inline struct ip_addr* str2ip6(str* st)
-{
-       int i, idx1, rest;
-       int no_colons;
-       int double_colon;
-       int hex;
-       static struct ip_addr ip;
-       unsigned short* addr_start;
-       unsigned short addr_end[8];
-       unsigned short* addr;
-       unsigned char* limit;
-       unsigned char* s;
-       
-       /* just in case that e.g. the VIA parser get confused */
-       if(unlikely(!st->s || st->len <= 0)) {
-               LM_ERR("invalid name, no conversion to IP address possible\n");
-               return 0;
-       }
-       /* init */
-       if ((st->len) && (st->s[0]=='[')){
-               /* skip over [ ] */
-               if (st->s[st->len-1]!=']') goto error_char;
-               s=(unsigned char*)(st->s+1);
-               limit=(unsigned char*)(st->s+st->len-1);
-       }else{
-               s=(unsigned char*)st->s;
-               limit=(unsigned char*)(st->s+st->len);
-       }
-       i=idx1=rest=0;
-       double_colon=0;
-       no_colons=0;
-       ip.af=AF_INET6;
-       ip.len=16;
-       addr_start=ip.u.addr16;
-       addr=addr_start;
-       memset(addr_start, 0 , 8*sizeof(unsigned short));
-       memset(addr_end, 0 , 8*sizeof(unsigned short));
-       for (; s<limit; s++){
-               if (*s==':'){
-                       no_colons++;
-                       if (no_colons>7) goto error_too_many_colons;
-                       if (double_colon){
-                               idx1=i;
-                               i=0;
-                               if (addr==addr_end) goto error_colons;
-                               addr=addr_end;
-                       }else{
-                               double_colon=1;
-                               addr[i]=htons(addr[i]);
-                               i++;
-                       }
-               }else if ((hex=HEX2I(*s))>=0){
-                               addr[i]=addr[i]*16+hex;
-                               double_colon=0;
-               }else{
-                       /* error, unknown char */
-                       goto error_char;
-               }
-       }
-       if (!double_colon){ /* not ending in ':' */
-               addr[i]=htons(addr[i]);
-               i++; 
-       }
-       /* if address contained '::' fix it */
-       if (addr==addr_end){
-               rest=8-i-idx1;
-               memcpy(addr_start+idx1+rest, addr_end, i*sizeof(unsigned short));
-       }else{
-               /* no double colons inside */
-               if (no_colons<7) goto error_too_few_colons;
-       }
-/*
-       DBG("str2ip6: idx1=%d, rest=%d, no_colons=%d, hex=%x\n",
-                       idx1, rest, no_colons, hex);
-       DBG("str2ip6: address %x:%x:%x:%x:%x:%x:%x:%x\n", 
-                       addr_start[0], addr_start[1], addr_start[2],
-                       addr_start[3], addr_start[4], addr_start[5],
-                       addr_start[6], addr_start[7] );
-*/
-       return &ip;
-
-error_too_many_colons:
-       DBG("str2ip6: ERROR: too many colons in [%.*s]\n", st->len, st->s);
-       return 0;
-
-error_too_few_colons:
-       DBG("str2ip6: ERROR: too few colons in [%.*s]\n", st->len, st->s);
-       return 0;
-
-error_colons:
-       DBG("str2ip6: ERROR: too many double colons in [%.*s]\n", st->len, st->s);
-       return 0;
-
-error_char:
-       /*
-       DBG("str2ip6: WARNING: unexpected char %c in  [%.*s]\n", *s, st->len,
-                       st->s);*/
-       return 0;
-}
-
-
+int str2ipbuf(str* st, ip_addr_t* ipb);
+int str2ip6buf(str* st, ip_addr_t* ipb);
+int str2ipxbuf(str* st, ip_addr_t* ipb);
+ip_addr_t* str2ip(str* st);
+ip_addr_t* str2ip6(str* st);
+ip_addr_t* str2ipx(str* st);
 
 struct hostent* _sip_resolvehost(str* name, unsigned short* port, char* proto);
 
@@ -376,7 +227,7 @@ struct hostent* _sip_resolvehost(str* name, unsigned short* port, char* proto);
 static inline struct hostent* _resolvehost(char* name)
 {
        static struct hostent* he=0;
-#ifdef HAVE_GETIPNODEBYNAME 
+#ifdef HAVE_GETIPNODEBYNAME
        int err;
        static struct hostent* he2=0;
 #endif