1145519Sdarrenr/*	$FreeBSD$	*/
2145510Sdarrenr
3170268Sdarrenr/*
4255332Scy * Copyright (C) 2012 by Darren Reed.
5255332Scy *
6255332Scy * See the IPFILTER.LICENCE file for details on licencing.
7255332Scy *
8255332Scy * $Id$
9255332Scy */
10170268Sdarrenr
11145510Sdarrenr#include "ipf.h"
12255332Scy#include <ctype.h>
13145510Sdarrenr
14255332Scyint getport(fr, name, port, proto)
15255332Scy	frentry_t *fr;
16255332Scy	char *name, *proto;
17255332Scy	u_short *port;
18145510Sdarrenr{
19145510Sdarrenr	struct protoent *p;
20145510Sdarrenr	struct servent *s;
21145510Sdarrenr	u_short p1;
22145510Sdarrenr
23145510Sdarrenr	if (fr == NULL || fr->fr_type != FR_T_IPF) {
24255332Scy		s = getservbyname(name, proto);
25145510Sdarrenr		if (s != NULL) {
26145510Sdarrenr			*port = s->s_port;
27145510Sdarrenr			return 0;
28145510Sdarrenr		}
29255332Scy
30255332Scy		if (ISDIGIT(*name)) {
31255332Scy			int portval = atoi(name);
32255332Scy			if (portval < 0 || portval > 65535)
33255332Scy				return -1;
34255332Scy			*port = htons((u_short)portval);
35255332Scy			return 0;
36255332Scy		}
37145510Sdarrenr		return -1;
38145510Sdarrenr	}
39145510Sdarrenr
40161357Sguido	/*
41161357Sguido	 * Some people will use port names in rules without specifying
42161357Sguido	 * either TCP or UDP because it is implied by the group head.
43161357Sguido	 * If we don't know the protocol, then the best we can do here is
44161357Sguido	 * to take either only the TCP or UDP mapping (if one or the other
45161357Sguido	 * is missing) or make sure both of them agree.
46161357Sguido	 */
47161357Sguido	if (fr->fr_proto == 0) {
48161357Sguido		s = getservbyname(name, "tcp");
49161357Sguido		if (s != NULL)
50161357Sguido			p1 = s->s_port;
51161357Sguido		else
52161357Sguido			p1 = 0;
53161357Sguido		s = getservbyname(name, "udp");
54161357Sguido		if (s != NULL) {
55161357Sguido			if (p1 != s->s_port)
56161357Sguido				return -1;
57161357Sguido		}
58161357Sguido		if ((p1 == 0) && (s == NULL))
59161357Sguido			return -1;
60161357Sguido		if (p1)
61161357Sguido			*port = p1;
62161357Sguido		else
63161357Sguido			*port = s->s_port;
64161357Sguido		return 0;
65161357Sguido	}
66161357Sguido
67145510Sdarrenr	if ((fr->fr_flx & FI_TCPUDP) != 0) {
68145510Sdarrenr		/*
69145510Sdarrenr		 * If a rule is "tcp/udp" then check that both TCP and UDP
70145510Sdarrenr		 * mappings for this protocol name match ports.
71145510Sdarrenr		 */
72145510Sdarrenr		s = getservbyname(name, "tcp");
73145510Sdarrenr		if (s == NULL)
74145510Sdarrenr			return -1;
75145510Sdarrenr		p1 = s->s_port;
76145510Sdarrenr		s = getservbyname(name, "udp");
77145510Sdarrenr		if (s == NULL || s->s_port != p1)
78145510Sdarrenr			return -1;
79145510Sdarrenr		*port = p1;
80145510Sdarrenr		return 0;
81145510Sdarrenr	}
82145510Sdarrenr
83145510Sdarrenr	p = getprotobynumber(fr->fr_proto);
84145510Sdarrenr	s = getservbyname(name, p ? p->p_name : NULL);
85145510Sdarrenr	if (s != NULL) {
86145510Sdarrenr		*port = s->s_port;
87145510Sdarrenr		return 0;
88145510Sdarrenr	}
89145510Sdarrenr	return -1;
90145510Sdarrenr}
91