xref: /netbsd-src/external/bsd/ipf/dist/lib/getport.c (revision 13885a665959c62f13a82b3caedf986eaa17aa31)
1*13885a66Sdarrenr /*	$NetBSD: getport.c,v 1.2 2012/07/22 14:27:36 darrenr Exp $	*/
2bc4097aaSchristos 
3bc4097aaSchristos /*
4c9d5dc6cSdarrenr  * Copyright (C) 2012 by Darren Reed.
5bc4097aaSchristos  *
6bc4097aaSchristos  * See the IPFILTER.LICENCE file for details on licencing.
7bc4097aaSchristos  *
8*13885a66Sdarrenr  * Id: getport.c,v 1.1.1.2 2012/07/22 13:44:38 darrenr Exp $
9bc4097aaSchristos  */
10bc4097aaSchristos 
11bc4097aaSchristos #include "ipf.h"
12bc4097aaSchristos #include <ctype.h>
13bc4097aaSchristos 
getport(fr,name,port,proto)14bc4097aaSchristos int getport(fr, name, port, proto)
15bc4097aaSchristos 	frentry_t *fr;
16bc4097aaSchristos 	char *name, *proto;
17bc4097aaSchristos 	u_short *port;
18bc4097aaSchristos {
19bc4097aaSchristos 	struct protoent *p;
20bc4097aaSchristos 	struct servent *s;
21bc4097aaSchristos 	u_short p1;
22bc4097aaSchristos 
23bc4097aaSchristos 	if (fr == NULL || fr->fr_type != FR_T_IPF) {
24bc4097aaSchristos 		s = getservbyname(name, proto);
25bc4097aaSchristos 		if (s != NULL) {
26bc4097aaSchristos 			*port = s->s_port;
27bc4097aaSchristos 			return 0;
28bc4097aaSchristos 		}
29bc4097aaSchristos 
30bc4097aaSchristos 		if (ISDIGIT(*name)) {
31bc4097aaSchristos 			int portval = atoi(name);
32bc4097aaSchristos 			if (portval < 0 || portval > 65535)
33bc4097aaSchristos 				return -1;
34bc4097aaSchristos 			*port = htons((u_short)portval);
35bc4097aaSchristos 			return 0;
36bc4097aaSchristos 		}
37bc4097aaSchristos 		return -1;
38bc4097aaSchristos 	}
39bc4097aaSchristos 
40bc4097aaSchristos 	/*
41bc4097aaSchristos 	 * Some people will use port names in rules without specifying
42bc4097aaSchristos 	 * either TCP or UDP because it is implied by the group head.
43bc4097aaSchristos 	 * If we don't know the protocol, then the best we can do here is
44bc4097aaSchristos 	 * to take either only the TCP or UDP mapping (if one or the other
45bc4097aaSchristos 	 * is missing) or make sure both of them agree.
46bc4097aaSchristos 	 */
47bc4097aaSchristos 	if (fr->fr_proto == 0) {
48bc4097aaSchristos 		s = getservbyname(name, "tcp");
49bc4097aaSchristos 		if (s != NULL)
50bc4097aaSchristos 			p1 = s->s_port;
51bc4097aaSchristos 		else
52bc4097aaSchristos 			p1 = 0;
53bc4097aaSchristos 		s = getservbyname(name, "udp");
54bc4097aaSchristos 		if (s != NULL) {
55bc4097aaSchristos 			if (p1 != s->s_port)
56bc4097aaSchristos 				return -1;
57bc4097aaSchristos 		}
58bc4097aaSchristos 		if ((p1 == 0) && (s == NULL))
59bc4097aaSchristos 			return -1;
60bc4097aaSchristos 		if (p1)
61bc4097aaSchristos 			*port = p1;
62bc4097aaSchristos 		else
63bc4097aaSchristos 			*port = s->s_port;
64bc4097aaSchristos 		return 0;
65bc4097aaSchristos 	}
66bc4097aaSchristos 
67bc4097aaSchristos 	if ((fr->fr_flx & FI_TCPUDP) != 0) {
68bc4097aaSchristos 		/*
69bc4097aaSchristos 		 * If a rule is "tcp/udp" then check that both TCP and UDP
70bc4097aaSchristos 		 * mappings for this protocol name match ports.
71bc4097aaSchristos 		 */
72bc4097aaSchristos 		s = getservbyname(name, "tcp");
73bc4097aaSchristos 		if (s == NULL)
74bc4097aaSchristos 			return -1;
75bc4097aaSchristos 		p1 = s->s_port;
76bc4097aaSchristos 		s = getservbyname(name, "udp");
77bc4097aaSchristos 		if (s == NULL || s->s_port != p1)
78bc4097aaSchristos 			return -1;
79bc4097aaSchristos 		*port = p1;
80bc4097aaSchristos 		return 0;
81bc4097aaSchristos 	}
82bc4097aaSchristos 
83bc4097aaSchristos 	p = getprotobynumber(fr->fr_proto);
84bc4097aaSchristos 	s = getservbyname(name, p ? p->p_name : NULL);
85bc4097aaSchristos 	if (s != NULL) {
86bc4097aaSchristos 		*port = s->s_port;
87bc4097aaSchristos 		return 0;
88bc4097aaSchristos 	}
89bc4097aaSchristos 	return -1;
90bc4097aaSchristos }
91