1 /*
2 ** Copyright 1998 - 2011 Double Precision, Inc.
3 ** See COPYING for distribution information.
4 */
5 
6 #include	"rfc1035.h"
7 #include	<string.h>
8 #include	<errno.h>
9 
10 
11 static int ptr(struct rfc1035_res *, const void *, int,
12 	       void (*)(const char *, void *),
13 	       void *);
14 
save_name(const char * name,void * void_arg)15 static void save_name(const char *name, void *void_arg)
16 {
17 	strcpy((char *)void_arg, name);
18 }
19 
rfc1035_ptr(struct rfc1035_res * res,const RFC1035_ADDR * addr,char * name)20 int rfc1035_ptr(struct rfc1035_res *res, const RFC1035_ADDR *addr,
21 		  char *name)
22 {
23 	return rfc1035_ptr_x(res, addr, save_name, name);
24 }
25 
26 /* Convenient function to do reverse IP lookup */
27 #if	RFC1035_IPV6
28 
rfc1035_ptr_x(struct rfc1035_res * res,const RFC1035_ADDR * addr,void (* cb_func)(const char *,void *),void * cb_arg)29 int rfc1035_ptr_x(struct rfc1035_res *res, const RFC1035_ADDR *addr,
30 		  void (*cb_func)(const char *, void *),
31 		  void *cb_arg)
32 {
33 struct	in_addr	in4;
34 
35 	if (IN6_IS_ADDR_V4MAPPED(addr))
36 	{
37 		rfc1035_ipv6to4(&in4, addr);
38 		if (ptr(res, &in4, AF_INET, cb_func, cb_arg) == 0) return (0);
39 		return (-1);
40 	}
41 	return (ptr(res, addr, AF_INET6, cb_func,cb_arg));
42 }
43 
44 #else
rfc1035_ptr_x(struct rfc1035_res * res,const RFC1035_ADDR * a,void (* cb_func)(const char *,void *),void * cb_arg)45 int rfc1035_ptr_x(struct rfc1035_res *res, const RFC1035_ADDR *a,
46 		  void (*cb_func)(const char *, void *),
47 		  void *cb_arg)
48 {
49 	return (ptr(res, a, AF_INET, cb_func, cb_arg));
50 }
51 #endif
52 
ptr(struct rfc1035_res * res,const void * addr,int af,void (* cb_func)(const char *,void *),void * cb_arg)53 static int ptr(struct rfc1035_res *res, const void *addr, int af,
54 	       void (*cb_func)(const char *, void *),
55 	       void *cb_arg)
56 {
57 struct	rfc1035_reply *reply;
58 int	n;
59 char	name[256], ptrbuf[256];
60 
61 #if	RFC1035_IPV6
62 
63 	if (af == AF_INET6)
64 	{
65 	const char *sin6=(const char *)addr;
66 	unsigned i;
67 
68 		*name=0;
69 		for (i=sizeof(struct in6_addr); i; )
70 		{
71 		char	buf[10];
72 
73 			--i;
74 			sprintf(buf, "%x.%x.",
75 				(int)(unsigned char)(sin6[i] & 0x0F),
76 				(int)(unsigned char)((sin6[i] >> 4) & 0x0F));
77 			strcat(name, buf);
78 		}
79 		strcat(name, "ip6.arpa");
80 	}
81 	else
82 #endif
83 	if (af != AF_INET)
84 	{
85 		errno=ENOENT;
86 		return (-1); /* hard error */
87 	}
88 	else
89 	{
90 	const char *p;
91 	unsigned char a=0,b=0,c=0,d=0;
92 	struct	in_addr	ia;
93 
94 		memcpy(&ia, addr, sizeof(ia));
95 		rfc1035_ntoa_ipv4(&ia, name);
96 		p=name;
97 
98 		while (*p >= '0' && *p <= '9')
99 			a= (int)a * 10 + (*p++ - '0');
100 		if (*p)	p++;
101 		while (*p >= '0' && *p <= '9')
102 			b= (int)b * 10 + (*p++ - '0');
103 		if (*p)	p++;
104 		while (*p >= '0' && *p <= '9')
105 			c= (int)c * 10 + (*p++ - '0');
106 		if (*p)	p++;
107 		while (*p >= '0' && *p <= '9')
108 			d= (int)d * 10 + (*p++ - '0');
109 
110 		sprintf(name, "%d.%d.%d.%d.in-addr.arpa",
111 			(int)d, (int)c, (int)b, (int)a);
112 	}
113 
114 	if (rfc1035_resolve_cname(res, name,
115 		RFC1035_TYPE_PTR, RFC1035_CLASS_IN, &reply, 0) < 0 ||
116 		reply == 0 ||
117 		(n=rfc1035_replysearch_an( res, reply, name, RFC1035_TYPE_PTR,
118 			RFC1035_CLASS_IN, 0)) < 0 ||
119 		rfc1035_replyhostname(reply, reply->allrrs[n]->rr.domainname,
120 			ptrbuf) == 0)
121 	{
122 		if (reply && reply->rcode != RFC1035_RCODE_NXDOMAIN &&
123 			reply->rcode != RFC1035_RCODE_NOERROR)
124 		{
125 			rfc1035_replyfree(reply);
126 			errno=EAGAIN;
127 			return (-1);
128 		}
129 
130 		if (reply) rfc1035_replyfree(reply);
131 		errno=ENOENT;
132 		return (-1); /* hard error */
133 	}
134 
135 	(*cb_func)(ptrbuf, cb_arg);
136 
137 	while ((n=rfc1035_replysearch_an(res, reply, name,
138 					 RFC1035_TYPE_PTR,
139 					 RFC1035_CLASS_IN, n+1)) >= 0)
140 	{
141 		if (rfc1035_replyhostname(reply,
142 					  reply->allrrs[n]->rr.domainname,
143 					  ptrbuf))
144 			(*cb_func)(ptrbuf, cb_arg);
145 	}
146 
147 	rfc1035_replyfree(reply);
148 	return (0);
149 }
150