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