View | Details | Raw Unified | Return to bug 200356 | Differences between
and this patch

Collapse All | Expand All

(-)mDNSPosix/nss_mdns.c (+336 lines)
Lines 2721-2723 Link Here
2721
2721
2722
    return -1;
2722
    return -1;
2723
}
2723
}
2724
2725
static NSS_METHOD_PROTOTYPE(__nss_bsdcompat_gethostbyname2_r);
2726
static NSS_METHOD_PROTOTYPE(__nss_bsdcompat_gethostbyaddr_r);
2727
static NSS_METHOD_PROTOTYPE(__nss_bsdcompat_getaddrinfo);
2728
2729
static ns_mtab methods[] = {
2730
	/* database, name, method, mdata */
2731
	{ NSDB_HOSTS, "gethostbyaddr_r", __nss_bsdcompat_gethostbyaddr_r, NULL },
2732
	{ NSDB_HOSTS, "gethostbyname2_r", __nss_bsdcompat_gethostbyname2_r, NULL },
2733
	{ NSDB_HOSTS, "getaddrinfo", __nss_bsdcompat_getaddrinfo, NULL },
2734
};
2735
2736
/*
2737
 * The prototype for gethostbyaddr_r is:
2738
 *	int gethostbyaddr_r(const void *addr, socklen_t len, int type,
2739
 *		struct hostent *ret, char *buf, size_t buflen,
2740
 *		struct hostent **result, int *h_errnop);
2741
 *
2742
 * nsdispatch calls gethostbyaddr_r as:
2743
 *       rval = _nsdispatch((void *)result, dtab, NSDB_HOSTS,
2744
 *           "gethostbyaddr_r", default_src, uaddr, len, af, hp, buf, buflen,
2745
 *           &ret_errno, h_errnop);
2746
 * which translates into us being (effectively) called as:
2747
 * rval = func(result, mdata, uaddr, len, type, ret, buf, buflen, &ret_errno, h_errnop)
2748
 * We turn result into a struct hostent **, set *result to NULL, and then
2749
 * call _nss_mdns_gethostbyaddr().
2750
 */
2751
static int
2752
__nss_bsdcompat_gethostbyaddr_r(void *retval, void *mdata __unused, va_list ap)
2753
{
2754
	const void	*addr;
2755
	socklen_t	len;
2756
	int		type;
2757
	struct hostent	*ret;
2758
	char		*buf;
2759
	size_t		buflen;
2760
	struct hostent	**result = (struct hostent**)retval;
2761
	int		*ret_errno;
2762
	int		*h_errnop;
2763
	enum nss_status	status;
2764
2765
	addr = va_arg(ap, const void*);
2766
	len = va_arg(ap, int);
2767
	type = va_arg(ap, int);
2768
	ret = va_arg(ap, struct hostent *);
2769
	buf = va_arg(ap, char *);
2770
	buflen = va_arg(ap, size_t);
2771
	ret_errno = va_arg(ap, int *);
2772
	h_errnop = va_arg(ap, int *);
2773
2774
	*result = NULL;
2775
	status = _nss_mdns_gethostbyaddr_r(addr, len, type, ret, buf, buflen, ret_errno, h_errnop);
2776
	status = __nss_compat_result(status, *h_errnop);
2777
	if (status == NS_SUCCESS)
2778
		*result = ret;
2779
	
2780
	return (status);
2781
}
2782
2783
/*
2784
 * This is a lot of guesswork on my part.
2785
 * nsdispatch calls getaddrinfo as:
2786
 *
2787
 * _nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo",
2788
 *	default_dns_files, hostname, pai)
2789
 *
2790
 * which translates to us being (effectively) called as:
2791
 * rval = func(result, mdata, hostname, pai)
2792
 * The first argument, result, is struct addrinfo **.
2793
 *
2794
 */
2795
2796
static struct addrinfo *
2797
get_one_ai(const char *hostname, int af, const struct addrinfo *hints)
2798
{
2799
	nss_status lookup_status;
2800
	hostent hostent_buf;
2801
	char buf[1024] = { 0 };
2802
	int err1, h_err1;
2803
	struct addrinfo *retval = NULL;
2804
	
2805
	memset(&hostent_buf, 0, sizeof(hostent_buf));
2806
	lookup_status = mdns_gethostbyname2(hostname,
2807
					    af,
2808
					    &hostent_buf,
2809
					    buf,
2810
					    sizeof(buf),
2811
					    &err1,
2812
					    &h_err1);
2813
	lookup_status = __nss_compat_result(lookup_status, h_err1);
2814
	if (lookup_status == NS_SUCCESS) {
2815
		// Great, we found it, now what?
2816
		retval = calloc(1, sizeof(struct addrinfo) + sizeof(struct sockaddr_storage));
2817
		if (retval) {
2818
			// Take advantage of c's scaling
2819
			retval->ai_addr = (struct sockaddr*)(retval + 1);
2820
			retval->ai_flags = hints->ai_flags;
2821
			retval->ai_socktype = hints->ai_socktype;
2822
			retval->ai_protocol = hints->ai_protocol;
2823
			retval->ai_family = hostent_buf.h_addrtype;
2824
			retval->ai_addrlen = hostent_buf.h_length;
2825
			retval->ai_addr->sa_len = hostent_buf.h_length;
2826
			retval->ai_addr->sa_family = retval->ai_family;
2827
			
2828
			if (retval->ai_family == PF_INET) {
2829
				struct sockaddr_in *sin = (void*)retval->ai_addr;
2830
				retval->ai_addrlen = sizeof(*sin);
2831
				memcpy(&sin->sin_addr, hostent_buf.h_addr, hostent_buf.h_length);
2832
			} else if (retval->ai_family == PF_INET6) {
2833
				struct sockaddr_in6 *sin = (void*)retval->ai_addr;
2834
				retval->ai_addrlen = sizeof(*sin);
2835
				memcpy(&sin->sin6_addr, hostent_buf.h_addr, hostent_buf.h_length);
2836
			} else {
2837
				retval->ai_addrlen = sizeof(struct sockaddr_storage);
2838
				memcpy(retval->ai_addr->sa_data,
2839
				       hostent_buf.h_addr,
2840
				       hostent_buf.h_length);
2841
			}
2842
			retval->ai_canonname = strdup(hostname);
2843
#ifdef DEBUG
2844
			fprintf(stderr, "%s:  ai_canonname = %s, ai_addrlen = %d\n", __FUNCTION__, retval->ai_canonname, (int)(retval->ai_addrlen));
2845
			{
2846
				char ascii[1024];
2847
				void *sin_ptr;
2848
2849
				if (retval->ai_family == PF_INET) {
2850
					struct sockaddr_in *sin = (void*)retval->ai_addr;
2851
					sin_ptr = &sin->sin_addr;
2852
				} else if (retval->ai_family == PF_INET6) {
2853
					struct sockaddr_in6 *sin6 = (void*)retval->ai_addr;
2854
					sin_ptr = &sin6->sin6_addr;
2855
				} else {
2856
					sin_ptr = &retval->ai_addr;
2857
				}
2858
				if (inet_ntop(retval->ai_family,
2859
					      sin_ptr,
2860
					      ascii,
2861
					      sizeof(ascii))) {
2862
					fprintf(stderr, "\tip = %s\n", ascii);
2863
				} else {
2864
					fprintf(stderr, "\tUnable to convert address to string\n");
2865
				}
2866
			}
2867
#endif
2868
		}
2869
	} 
2870
//#ifdef DEBUG
2871
	if (retval == NULL)
2872
		fprintf(stderr, "%s: returning %p, lookup_status = %d\n", __FUNCTION__, retval, lookup_status);
2873
//#endif
2874
	return retval;
2875
}
2876
2877
#ifdef DEBUG
2878
static void
2879
PrintAddrinfo(struct addrinfo *ai)
2880
{
2881
	char buf[1024];
2882
	void *sin_ptr;
2883
	if (ai == NULL)
2884
		return;
2885
	buf[0] = 0;
2886
	if (ai->ai_family == PF_INET) {
2887
		struct sockaddr_in *sin = (void*)ai->ai_addr;
2888
		sin_ptr = &sin->sin_addr;
2889
	} else if (ai->ai_family == PF_INET6) {
2890
		struct sockaddr_in6 *sin6 = (void*)ai->ai_addr;
2891
		sin_ptr = &sin6->sin6_addr;
2892
	} else {
2893
		sin_ptr = &ai->ai_addr;
2894
	}
2895
	inet_ntop(ai->ai_family, sin_ptr, buf, sizeof(buf));
2896
	
2897
	fprintf(stderr, "struct addrinfo {\n");
2898
	fprintf(stderr, "\tai_flags = %#x,\n", ai->ai_flags);
2899
	fprintf(stderr, "\tai_family = %d,\n", ai->ai_family);
2900
	fprintf(stderr, "\tai_socktype = %d,\n", ai->ai_socktype);
2901
	fprintf(stderr, "\tai_protocol = %d,\n", ai->ai_protocol);
2902
	fprintf(stderr, "\tai_addrlen = %d,\n", (int)ai->ai_addrlen);
2903
	fprintf(stderr, "\tai_addr = %s,\n", buf[0] ? buf : "(unknown?)");
2904
	fprintf(stderr, "}\n");
2905
	
2906
}
2907
#endif
2908
2909
static int
2910
__nss_bsdcompat_getaddrinfo(void *result, void *mdata __unused, va_list ap)
2911
{
2912
	const char *hostname;
2913
	const struct addrinfo *pai;
2914
	struct addrinfo **retval = (struct addrinfo **)result;
2915
2916
	hostname = va_arg(ap, const char *);
2917
	pai = va_arg(ap, const struct addrinfo *);
2918
2919
	*retval = NULL;
2920
	// Some quick error checking
2921
	if (hostname == NULL || pai == NULL) {
2922
#ifdef DEBUG
2923
		fprintf(stderr, "%s(%d):  Returning NS_UNAVAIL\n", __FUNCTION__, __LINE__);
2924
#endif
2925
		return (NS_UNAVAIL);
2926
	}
2927
	
2928
#ifdef DEBUG
2929
	{
2930
		fprintf(stderr,
2931
			"%s:  *retval = %p, hostname = %s, pai = { ai_flags = %#x, ai_family = %#x, ai_socktype = %#x, ai_protocol = %#x }\n",
2932
			__FUNCTION__, *retval, hostname, pai->ai_flags, pai->ai_family, pai->ai_socktype, pai->ai_protocol);
2933
	}
2934
#endif
2935
	
2936
	/*
2937
	 * We can do three kinds of searches:
2938
	 * PF_UNSPEC:  whichever kind we find
2939
	 * PF_INET:  An IPv4 address
2940
	 * PF_INET6: An IPv6 address.
2941
	 * We'll use mdns_gethostbyname2_r(),
2942
	 * which will handle PF_INET or PF_INET6.
2943
	 * Buf if we're given PF_UNSPEC we should try each in
2944
	 * succession, I suppose?  Or perhaps we're supposed to
2945
	 * return both if we can?
2946
	 */
2947
	switch (pai->ai_family) {
2948
	case PF_INET:
2949
	case PF_INET6:
2950
		*retval = get_one_ai(hostname, pai->ai_family, pai);
2951
#ifdef DEBUG
2952
		fprintf(stderr, "Only needed one, *retval = %p\n", *retval);
2953
#endif
2954
		break;
2955
	case PF_UNSPEC:
2956
	{
2957
		// Do both!
2958
		struct addrinfo *ipv4, *ipv6;
2959
		struct addrinfo sentinel, *tmp = &sentinel;
2960
		memset(&sentinel, 0, sizeof(sentinel));
2961
		if ((ipv6 = get_one_ai(hostname, PF_INET6, pai)) != NULL) {
2962
			tmp->ai_next = ipv6;
2963
			tmp = ipv6;
2964
		}
2965
		if ((ipv4 = get_one_ai(hostname, PF_INET, pai)) != NULL) {
2966
			tmp->ai_next = ipv4;
2967
			tmp = ipv4;
2968
		}
2969
		*retval = sentinel.ai_next;
2970
	}
2971
	break;
2972
	default:
2973
#ifdef DEBUG
2974
		fprintf(stderr, "%s(%d):  Returning NS_UNAVAIL\n", __FUNCTION__, __LINE__);
2975
#endif
2976
		return (NS_UNAVAIL);
2977
	}
2978
2979
	if (*retval == NULL) {
2980
#ifdef DEBUG
2981
		fprintf(stderr, "%s(%d):  Returning NS_NOTFOUND\n", __FUNCTION__, __LINE__);
2982
#endif
2983
		return (NS_NOTFOUND);
2984
	}
2985
	
2986
#ifdef DEBUG
2987
	{
2988
		fprintf(stderr, "%s:  *retval = %p\n", __FUNCTION__, *retval);
2989
	}
2990
	struct addrinfo *tai;
2991
	for (tai = *retval; tai; tai = tai->ai_next) {
2992
		PrintAddrinfo(tai);
2993
	}
2994
#endif
2995
	return (NS_SUCCESS);
2996
}
2997
2998
/*
2999
 * The prototype for gethostbyname2_r is
3000
 * gethostbyname2_r(const char *name, int af, struct hostent *he, char *buffer,
3001
 *	size_t buflen, struct hostent **result, int *h_errnop)
3002
 *
3003
 * nsdispatch calls gethostbyname2_r as
3004
 *       rval = _nsdispatch((void *)result, dtab, NSDB_HOSTS,
3005
 *           "gethostbyname2_r", default_src, name, af, hp, buf, buflen,
3006
 *           &ret_errno, h_errnop);
3007
 * which translates into us being (effectively) called as:
3008
 * rval = func(result, mdata, name, af, hp, buf, buflen, &ret_errno, h_errnop)
3009
 * We turn result into a struct hostent **, set *result to NULL, and then
3010
 * call _nss_mdns_gethostbyname2_r()
3011
 */
3012
static int
3013
__nss_bsdcompat_gethostbyname2_r(void *retval, void *mdata __unused,
3014
				 va_list ap)
3015
{
3016
	char            *buf;
3017
	const char      *name;
3018
	int             *h_errnop;
3019
	struct hostent  *hp;
3020
	struct hostent  **resultp = (struct hostent **)retval;
3021
	int              af;
3022
	size_t           buflen;
3023
	int              ret_errno;
3024
	enum nss_status  status;
3025
3026
	name = va_arg(ap, char *);
3027
	af = va_arg(ap, int);
3028
	hp = va_arg(ap, struct hostent *);
3029
	buf = va_arg(ap, char *);
3030
	buflen = va_arg(ap, size_t);
3031
	ret_errno = va_arg(ap, int);
3032
	h_errnop = va_arg(ap, int *);
3033
3034
	if (hp == NULL)
3035
		return (NS_UNAVAIL);
3036
3037
	*resultp = NULL;
3038
	status = _nss_mdns_gethostbyname2_r(name, af, hp, buf, buflen,
3039
					    &ret_errno, h_errnop);
3040
3041
	status = __nss_compat_result(status, *h_errnop);
3042
	if (status == NS_SUCCESS)
3043
		*resultp = hp;
3044
	return (status);
3045
}
3046
3047
ns_mtab *
3048
nss_module_register(const char *source __unused, unsigned int *mtabsize,
3049
		    nss_module_unregister_fn *unreg)
3050
{
3051
#ifdef DEBUG
3052
	{
3053
		fprintf(stderr, "%s(%s, %p, %p)\n", __FUNCTION__, source, mtabsize, unreg);
3054
	}
3055
#endif
3056
	*mtabsize = sizeof(methods)/sizeof(methods[0]);
3057
	*unreg = NULL;
3058
	return (methods);
3059
}

Return to bug 200356