2 * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
4 * This software is subject to the conditions detailed
5 * in the LICENCE file provided within the distribution */
12 // This is a workaround for <sys/uio.h> troubles on FreeBSD, HPUX, OpenBSD.
13 // Needed here because on some systems <sys/uio.h> gets included by things
14 // like <sys/socket.h>
31 #include <sys/socket.h>
32 #include <sys/syslog.h>
33 #include <sys/ioctl.h>
35 #if __FreeBSD_version >= 300000
36 # include <net/if_var.h>
38 #include <netinet/in.h>
39 #include <netinet/in_systm.h>
40 #include <netinet/ip.h>
41 #include <netinet/ip_icmp.h>
42 #ifndef TCP_PAWS_IDLE // IRIX
43 # include <netinet/tcp.h>
45 #include <netinet/tcp.h>
46 #include <netinet/udp.h>
47 #include <arpa/inet.h>
49 #include <sys/types.h>
50 #include <sys/queue.h>
51 #include <sys/socket.h>
60 #if !defined(__SVR4) && !defined(__svr4__) && defined(sun)
65 #include <netinet/ip_fw.h>
68 #include "../config.h"
85 #if defined(sun) && !defined(__SVR4) && !defined(__svr4__)
86 extern int ioctl
__P((int, int, void *));
89 #include "../upnpglobalvars.h"
92 int init_redirect(void) {
93 ipfw_exec(IP_FW_INIT
, NULL
, 0);
97 void shutdown_redirect(void) {
98 ipfw_exec(IP_FW_TERM
, NULL
, 0);
101 int add_redirect_rule2(
103 unsigned short eport
,
105 unsigned short iport
,
111 if (ipfw_validate_protocol(proto
) < 0)
113 if (ipfw_validate_ifname(ifname
) < 0)
116 memset(&rule
, 0, sizeof(struct ip_fw
));
117 rule
.version
= IP_FW_CURRENT_API_VERSION
;
118 //rule.fw_number = 1000; // rule number
119 rule
.context
= (void *)desc
; // TODO keep this?
120 rule
.fw_prot
= proto
; // protocol
121 rule
.fw_flg
|= IP_FW_F_IIFACE
; // interfaces to check
122 rule
.fw_flg
|= IP_FW_F_IIFNAME
; // interfaces to check by name
123 rule
.fw_flg
|= (IP_FW_F_IN
| IP_FW_F_OUT
); // packet direction
124 rule
.fw_flg
|= IP_FW_F_FWD
; // forward action
125 #ifdef USE_IFNAME_IN_RULES
126 if (ifname
!= NULL
) {
127 strcpy(rule
.fw_in_if
.fu_via_if
.name
, ifname
); // src interface
128 rule
.fw_in_if
.fu_via_if
.unit
= -1;
131 if (inet_aton(iaddr
, &rule
.fw_out_if
.fu_via_ip
) == 0) {
132 syslog(LOG_ERR
, "inet_aton(): %m");
135 memcpy(&rule
.fw_dst
, &rule
.fw_out_if
.fu_via_ip
, sizeof(struct in_addr
));
136 memcpy(&rule
.fw_fwd_ip
.sin_addr
, &rule
.fw_out_if
.fu_via_ip
, sizeof(struct in_addr
));
137 rule
.fw_dmsk
.s_addr
= INADDR_BROADCAST
;
138 IP_FW_SETNDSTP(&rule
, 1); // number of external ports
139 rule
.fw_uar
.fw_pts
[0] = eport
; // external port
140 rule
.fw_fwd_ip
.sin_port
= iport
; // internal port
142 return ipfw_exec(IP_FW_ADD
, &rule
, sizeof(rule
));
145 /* get_redirect_rule()
146 * return value : 0 success (found)
147 * -1 = error or rule not found */
148 int get_redirect_rule(
150 unsigned short eport
,
154 unsigned short * iport
,
160 int i
, count_rules
, total_rules
= 0;
161 struct ip_fw
* rules
= NULL
;
163 if (ipfw_validate_protocol(proto
) < 0)
165 if (ipfw_validate_ifname(ifname
) < 0)
169 count_rules
= ipfw_fetch_ruleset(&rules
, &total_rules
, 10);
172 } while (count_rules
== 10);
174 for (i
=0; i
<total_rules
-1; i
++) {
175 const struct ip_fw
const * ptr
= &rules
[i
];
176 if (proto
== ptr
->fw_prot
&& eport
== ptr
->fw_uar
.fw_pts
[0]) {
178 *packets
= ptr
->fw_pcnt
;
180 *bytes
= ptr
->fw_bcnt
;
182 *iport
= ptr
->fw_fwd_ip
.sin_port
;
183 if (desc
!= NULL
&& desclen
> 0)
184 strlcpy(desc
, "", desclen
); // TODO should we copy ptr->context?
185 if (iaddr
!= NULL
&& iaddrlen
> 0) {
186 if (inet_ntop(AF_INET
, &ptr
->fw_out_if
.fu_via_ip
, iaddr
, iaddrlen
) == NULL
) {
187 syslog(LOG_ERR
, "inet_ntop(): %m");
191 // And what if we found more than 1 matching rule?
192 ipfw_free_ruleset(&rules
);
199 ipfw_free_ruleset(&rules
);
203 int delete_redirect_rule(
205 unsigned short eport
,
208 int i
, count_rules
, total_rules
= 0;
209 struct ip_fw
* rules
= NULL
;
211 if (ipfw_validate_protocol(proto
) < 0)
213 if (ipfw_validate_ifname(ifname
) < 0)
217 count_rules
= ipfw_fetch_ruleset(&rules
, &total_rules
, 10);
220 } while (count_rules
== 10);
222 for (i
=0; i
<total_rules
-1; i
++) {
223 const struct ip_fw
const * ptr
= &rules
[i
];
224 if (proto
== ptr
->fw_prot
&& eport
== ptr
->fw_uar
.fw_pts
[0]) {
225 if (ipfw_exec(IP_FW_DEL
, (struct ip_fw
*)ptr
, sizeof(*ptr
)) < 0)
227 // And what if we found more than 1 matching rule?
228 ipfw_free_ruleset(&rules
);
235 ipfw_free_ruleset(&rules
);
239 int add_filter_rule2(
242 unsigned short eport
,
243 unsigned short iport
,
250 int delete_filter_rule(
252 unsigned short eport
,
258 int get_redirect_rule_by_index(
261 unsigned short * eport
,
264 unsigned short * iport
,
272 struct ip_fw
* rules
= NULL
;
274 if (index
< 0) // TODO shouldn't we also validate the maximum?
277 ipfw_fetch_ruleset(&rules
, &total_rules
, index
+ 1);
279 if (total_rules
== index
+ 1) {
280 const struct ip_fw
const * ptr
= &rules
[index
];
282 *proto
= ptr
->fw_prot
;
284 *eport
= ptr
->fw_uar
.fw_pts
[0];
286 *iport
= ptr
->fw_fwd_ip
.sin_port
;
288 strlcpy(ifname
, ptr
->fw_in_if
.fu_via_if
.name
, IFNAMSIZ
); // TODO does it work?
290 *packets
= ptr
->fw_pcnt
;
292 *bytes
= ptr
->fw_bcnt
;
294 *iport
= ptr
->fw_fwd_ip
.sin_port
;
295 if (desc
!= NULL
&& desclen
> 0)
296 strlcpy(desc
, "", desclen
); // TODO should we copy ptr->context?
297 if (iaddr
!= NULL
&& iaddrlen
> 0) {
298 if (inet_ntop(AF_INET
, &ptr
->fw_out_if
.fu_via_ip
, iaddr
, iaddrlen
) == NULL
) {
299 syslog(LOG_ERR
, "inet_ntop(): %m");
303 ipfw_free_ruleset(&rules
);
309 ipfw_free_ruleset(&rules
);