getport.c revision 259065
1232950Stheraven/*	$FreeBSD: releng/10.0/contrib/ipfilter/lib/getport.c 255332 2013-09-06 23:11:19Z cy $	*/
2232950Stheraven
3232950Stheraven/*
4232950Stheraven * Copyright (C) 2012 by Darren Reed.
5232950Stheraven *
6232950Stheraven * See the IPFILTER.LICENCE file for details on licencing.
7232950Stheraven *
8232950Stheraven * $Id$
9232950Stheraven */
10232950Stheraven
11232950Stheraven#include "ipf.h"
12232950Stheraven#include <ctype.h>
13232950Stheraven
14232950Stheravenint getport(fr, name, port, proto)
15232950Stheraven	frentry_t *fr;
16232950Stheraven	char *name, *proto;
17232950Stheraven	u_short *port;
18232950Stheraven{
19232950Stheraven	struct protoent *p;
20232950Stheraven	struct servent *s;
21232950Stheraven	u_short p1;
22232950Stheraven
23232950Stheraven	if (fr == NULL || fr->fr_type != FR_T_IPF) {
24232950Stheraven		s = getservbyname(name, proto);
25232950Stheraven		if (s != NULL) {
26232950Stheraven			*port = s->s_port;
27227825Stheraven			return 0;
28227825Stheraven		}
29227825Stheraven
30227825Stheraven		if (ISDIGIT(*name)) {
31227825Stheraven			int portval = atoi(name);
32233235Stheraven			if (portval < 0 || portval > 65535)
33233235Stheraven				return -1;
34233235Stheraven			*port = htons((u_short)portval);
35233235Stheraven			return 0;
36227825Stheraven		}
37233235Stheraven		return -1;
38233235Stheraven	}
39233235Stheraven
40233235Stheraven	/*
41233235Stheraven	 * Some people will use port names in rules without specifying
42233235Stheraven	 * either TCP or UDP because it is implied by the group head.
43233235Stheraven	 * If we don't know the protocol, then the best we can do here is
44233235Stheraven	 * to take either only the TCP or UDP mapping (if one or the other
45233235Stheraven	 * is missing) or make sure both of them agree.
46233235Stheraven	 */
47233235Stheraven	if (fr->fr_proto == 0) {
48233235Stheraven		s = getservbyname(name, "tcp");
49233235Stheraven		if (s != NULL)
50233235Stheraven			p1 = s->s_port;
51233235Stheraven		else
52233235Stheraven			p1 = 0;
53233235Stheraven		s = getservbyname(name, "udp");
54233235Stheraven		if (s != NULL) {
55233235Stheraven			if (p1 != s->s_port)
56233235Stheraven				return -1;
57233235Stheraven		}
58233235Stheraven		if ((p1 == 0) && (s == NULL))
59233235Stheraven			return -1;
60233235Stheraven		if (p1)
61233235Stheraven			*port = p1;
62233235Stheraven		else
63233235Stheraven			*port = s->s_port;
64233235Stheraven		return 0;
65233235Stheraven	}
66233235Stheraven
67233235Stheraven	if ((fr->fr_flx & FI_TCPUDP) != 0) {
68233235Stheraven		/*
69233235Stheraven		 * If a rule is "tcp/udp" then check that both TCP and UDP
70233235Stheraven		 * mappings for this protocol name match ports.
71233235Stheraven		 */
72233235Stheraven		s = getservbyname(name, "tcp");
73233235Stheraven		if (s == NULL)
74233235Stheraven			return -1;
75233235Stheraven		p1 = s->s_port;
76233235Stheraven		s = getservbyname(name, "udp");
77233235Stheraven		if (s == NULL || s->s_port != p1)
78233235Stheraven			return -1;
79233235Stheraven		*port = p1;
80233235Stheraven		return 0;
81233235Stheraven	}
82233235Stheraven
83233235Stheraven	p = getprotobynumber(fr->fr_proto);
84233235Stheraven	s = getservbyname(name, p ? p->p_name : NULL);
85233235Stheraven	if (s != NULL) {
86233235Stheraven		*port = s->s_port;
87233235Stheraven		return 0;
88233235Stheraven	}
89233235Stheraven	return -1;
90233235Stheraven}
91233235Stheraven