Пример #1
0
/* Firewall independant code which call the FW dependant code. */
int
upnp_get_redirection_infos(unsigned short eport, const char * protocol,
                           unsigned short * iport,
                           char * iaddr, int iaddrlen,
                           char * desc, int desclen,
                           char * rhost, int rhostlen,
                           unsigned int * leaseduration)
{
	int r;
	unsigned int timestamp;
	time_t current_time;

	if(desc && (desclen > 0))
		desc[0] = '\0';
	if(rhost && (rhostlen > 0))
		rhost[0] = '\0';
	r = get_redirect_rule(ext_if_name, eport, proto_atoi(protocol),
	                      iaddr, iaddrlen, iport, desc, desclen,
	                      rhost, rhostlen, &timestamp,
	                      0, 0);
	if(r == 0 &&
	   timestamp > 0 &&
	   timestamp > (unsigned int)(current_time = time(NULL))) {
		*leaseduration = timestamp - current_time;
	} else {
		*leaseduration = 0;
	}
	return r;
}
Пример #2
0
/* upnp_redirect()
 * calls OS/fw dependant implementation of the redirection.
 * protocol should be the string "TCP" or "UDP"
 * returns: 0 on success
 *          -1 failed to redirect
 *          -2 already redirected
 *          -3 permission check failed
 */
int
upnp_redirect(const char * rhost, unsigned short eport,
              const char * iaddr, unsigned short iport,
              const char * protocol, const char * desc,
              unsigned int leaseduration)
{
	int proto, r;
	char iaddr_old[32];
	unsigned short iport_old;
	struct in_addr address;
	unsigned int timestamp;

	proto = proto_atoi(protocol);
	if(inet_aton(iaddr, &address) < 0) {
		syslog(LOG_ERR, "inet_aton(%s) : %m", iaddr);
		return -1;
	}

	if(!check_upnp_rule_against_permissions(upnppermlist, num_upnpperm,
	                                        eport, address, iport)) {
		syslog(LOG_INFO, "redirection permission check failed for "
		                 "%hu->%s:%hu %s", eport, iaddr, iport, protocol);
		return -3;
	}
	r = get_redirect_rule(ext_if_name, eport, proto,
	                      iaddr_old, sizeof(iaddr_old), &iport_old, 0, 0,
	                      0, 0,
	                      &timestamp, 0, 0);
	if(r == 0) {
		/* if existing redirect rule matches redirect request return success
		 * xbox 360 does not keep track of the port it redirects and will
		 * redirect another port when receiving ConflictInMappingEntry */
		if(strcmp(iaddr, iaddr_old)==0 && iport==iport_old) {
			/* redirection allready exists */
			syslog(LOG_INFO, "port %hu %s already redirected to %s:%hu, replacing", eport, (proto==IPPROTO_TCP)?"tcp":"udp", iaddr_old, iport_old);
			/* remove and then add again */
			if(_upnp_delete_redir(eport, proto) < 0) {
				syslog(LOG_ERR, "failed to remove port mapping");
				return 0;
			}
		} else {
			syslog(LOG_INFO, "port %hu protocol %s already redirected to %s:%hu",
				eport, protocol, iaddr_old, iport_old);
			return -2;
		}
#ifdef CHECK_PORTINUSE
	} else if (port_in_use(ext_if_name, eport, proto, iaddr, iport) > 0) {
		syslog(LOG_INFO, "port %hu protocol %s already in use",
		       eport, protocol);
		return -2;
#endif /* CHECK_PORTINUSE */
	}
	
	timestamp = (leaseduration > 0) ? time(NULL) + leaseduration : 0;
	syslog(LOG_INFO, "redirecting port %hu to %s:%hu protocol %s for: %s",
		eport, iaddr, iport, protocol, desc);
	return upnp_redirect_internal(rhost, eport, iaddr, iport, proto,
	                              desc, timestamp);
}
Пример #3
0
int
upnp_get_redirection_infos(unsigned short eport, const char * protocol,
                           unsigned short * iport,
                           char * iaddr, int iaddrlen,
                           char * desc, int desclen)
{
    if(desc && (desclen > 0))
        desc[0] = '\0';
    return get_redirect_rule(ext_if_name, eport, proto_atoi(protocol),
                             iaddr, iaddrlen, iport, desc, desclen, 0, 0);
}
Пример #4
0
/* upnp_get_portmappings_in_range()
 * return a list of all "external" ports for which a port
 * mapping exists */
unsigned short *
upnp_get_portmappings_in_range(unsigned short startport,
                               unsigned short endport,
                               const char * protocol,
                               unsigned int * number)
{
	int proto;
	proto = proto_atoi(protocol);
	if(!number)
		return NULL;
	return get_portmappings_in_range(startport, endport, proto, number);
}
Пример #5
0
/* upnp_redirect()
 * calls OS/fw dependant implementation of the redirection.
 * protocol should be the string "TCP" or "UDP"
 * returns: 0 on success
 *          -1 failed to redirect
 *          -2 already redirected
 *          -3 permission check failed
 */
int
upnp_redirect(const char * rhost, unsigned short eport,
              const char * iaddr, unsigned short iport,
              const char * protocol, const char * desc,
              unsigned int leaseduration)
{
	int proto, r;
	char iaddr_old[32];
	unsigned short iport_old;
	struct in_addr address;
	unsigned int timestamp;

	proto = proto_atoi(protocol);
	if(inet_aton(iaddr, &address) < 0) {
		syslog(LOG_ERR, "inet_aton(%s) : %m", iaddr);
		return -1;
	}

	if(!check_upnp_rule_against_permissions(upnppermlist, num_upnpperm,
	                                        eport, address, iport)) {
		syslog(LOG_INFO, "redirection permission check failed for "
		                 "%hu->%s:%hu %s", eport, iaddr, iport, protocol);
		return -3;
	}
	r = get_redirect_rule(ext_if_name, eport, proto,
	                      iaddr_old, sizeof(iaddr_old), &iport_old, 0, 0,
	                      0, 0,
	                      &timestamp, 0, 0);
	if(r == 0) {
		/* if existing redirect rule matches redirect request return success
		 * xbox 360 does not keep track of the port it redirects and will
		 * redirect another port when receiving ConflictInMappingEntry */
		if(strcmp(iaddr, iaddr_old)==0 && iport==iport_old) {
			syslog(LOG_INFO, "ignoring redirect request as it matches existing redirect");
		} else {

			syslog(LOG_INFO, "port %hu protocol %s already redirected to %s:%hu",
				eport, protocol, iaddr_old, iport_old);
			return -2;
		}
	} else {
		timestamp = (leaseduration > 0) ? time(NULL) + leaseduration : 0;
		syslog(LOG_INFO, "redirecting port %hu to %s:%hu protocol %s for: %s",
			eport, iaddr, iport, protocol, desc);
		return upnp_redirect_internal(rhost, eport, iaddr, iport, proto,
		                              desc, timestamp);
	}

	return 0;
}
Пример #6
0
int
upnp_delete_redirection(unsigned short eport, const char * protocol)
{
	syslog(LOG_INFO, "removing redirect rule port %hu %s", eport, protocol);
	return _upnp_delete_redir(eport, proto_atoi(protocol));
}
Пример #7
0
/* reload_from_lease_file()
 * read lease_file and add the rules contained
 */
int reload_from_lease_file()
{
	FILE * fd;
	char * p;
	unsigned short eport, iport;
	char * proto;
	char * iaddr;
	char * desc;
	char * rhost;
	unsigned int leaseduration;
	unsigned int timestamp;
	time_t current_time;
	char line[128];
	int r;

	if(!lease_file) return -1;
	fd = fopen( lease_file, "r");
	if (fd==NULL) {
		syslog(LOG_DEBUG, "could not open lease file: %s", lease_file);
		return -1;
	}
	if(unlink(lease_file) < 0) {
		syslog(LOG_WARNING, "could not unlink file %s : %m", lease_file);
	}

	current_time = time(NULL);
	while(fgets(line, sizeof(line), fd)) {
		syslog(LOG_DEBUG, "parsing lease file line '%s'", line);
		proto = line;
		p = strchr(line, ':');
		if(!p) {
			syslog(LOG_ERR, "unrecognized data in lease file");
			continue;
		}
		*(p++) = '\0';
		iaddr = strchr(p, ':');
		if(!iaddr) {
			syslog(LOG_ERR, "unrecognized data in lease file");
			continue;
		}
		*(iaddr++) = '\0';
		eport = (unsigned short)atoi(p);
		p = strchr(iaddr, ':');
		if(!p) {
			syslog(LOG_ERR, "unrecognized data in lease file");
			continue;
		}
		*(p++) = '\0';
		iport = (unsigned short)atoi(p);
		p = strchr(p, ':');
		if(!p) {
			syslog(LOG_ERR, "unrecognized data in lease file");
			continue;
		}
		*(p++) = '\0';
		desc = strchr(p, ':');
		if(!desc) {
			syslog(LOG_ERR, "unrecognized data in lease file");
			continue;
		}
		*(desc++) = '\0';
		/*timestamp = (unsigned int)atoi(p);*/
		timestamp = (unsigned int)strtoul(p, NULL, 10);
		/* trim description */
		while(isspace(*desc))
			desc++;
		p = desc;
		while(*(p+1))
			p++;
		while(isspace(*p) && (p > desc))
			*(p--) = '\0';

		if(timestamp > 0) {
			if(timestamp <= (unsigned int)current_time) {
				syslog(LOG_NOTICE, "already expired lease in lease file");
				continue;
			} else {
				leaseduration = timestamp - current_time;
			}
		} else {
			leaseduration = 0;	/* default value */
		}
		rhost = NULL;
		r = upnp_redirect(rhost, eport, iaddr, iport, proto, desc, leaseduration);
		if(r == -1) {
			syslog(LOG_ERR, "Failed to redirect %hu -> %s:%hu protocol %s",
			       eport, iaddr, iport, proto);
		} else if(r == -2) {
			/* Add the redirection again to the lease file */
			lease_file_add(eport, iaddr, iport, proto_atoi(proto),
			               desc, timestamp);
		}
	}
	fclose(fd);

	return 0;
}
Пример #8
0
/* upnp_redirect()
 * calls OS/fw dependant implementation of the redirection.
 * protocol should be the string "TCP" or "UDP"
 * returns: 0 on success
 *          -1 failed to redirect
 *          -2 already redirected
 *          -3 permission check failed
 *          -4 already redirected (other mechanism)
 */
int
upnp_redirect(const char * rhost, unsigned short eport,
              const char * iaddr, unsigned short iport,
              const char * protocol, const char * desc,
              unsigned int leaseduration)
{
	int proto, r;
	char iaddr_old[32];
	char rhost_old[32];
	unsigned short iport_old;
	struct in_addr address;
	unsigned int timestamp;

	proto = proto_atoi(protocol);
	if(inet_aton(iaddr, &address) <= 0) {
		syslog(LOG_ERR, "inet_aton(%s) FAILED", iaddr);
		return -1;
	}

	if(!check_upnp_rule_against_permissions(upnppermlist, num_upnpperm,
	                                        eport, address, iport)) {
		syslog(LOG_INFO, "redirection permission check failed for "
		                 "%hu->%s:%hu %s", eport, iaddr, iport, protocol);
		return -3;
	}
	/* IGDv1 (WANIPConnection:1 Service Template Version 1.01 / Nov 12, 2001)
	 * - 2.2.20.PortMappingDescription :
	 *  Overwriting Previous / Existing Port Mappings:
	 * If the RemoteHost, ExternalPort, PortMappingProtocol and InternalClient
	 * are exactly the same as an existing mapping, the existing mapping values
	 * for InternalPort, PortMappingDescription, PortMappingEnabled and
	 * PortMappingLeaseDuration are overwritten.
	 *  Rejecting a New Port Mapping:
	 * In cases where the RemoteHost, ExternalPort and PortMappingProtocol
	 * are the same as an existing mapping, but the InternalClient is
	 * different, the action is rejected with an appropriate error.
	 *  Add or Reject New Port Mapping behavior based on vendor implementation:
	 * In cases where the ExternalPort, PortMappingProtocol and InternalClient
	 * are the same, but RemoteHost is different, the vendor can choose to
	 * support both mappings simultaneously, or reject the second mapping
	 * with an appropriate error.
	 *
	 * - 2.4.16.AddPortMapping
	 * This action creates a new port mapping or overwrites an existing
	 * mapping with the same internal client. If the ExternalPort and
	 * PortMappingProtocol pair is already mapped to another internal client,
	 * an error is returned.
	 *
	 * IGDv2 (WANIPConnection:2 Service Standardized DCP (SDCP) Sep 10, 2010)
	 * Protocol ExternalPort RemoteHost InternalClient Result
	 *     =         =           ≠           ≠         Failure
	 *     =         =           ≠           =         Failure or success
	 *                                                 (vendor specific)
	 *     =         =           =           ≠         Failure
	 *     =         =           =           =         Success (overwrite)
	 */
	rhost_old[0] = '\0';
	r = get_redirect_rule(ext_if_name, eport, proto,
	                      iaddr_old, sizeof(iaddr_old), &iport_old, 0, 0,
	                      rhost_old, sizeof(rhost_old),
	                      &timestamp, 0, 0);
	if(r == 0) {
		if(strcmp(iaddr, iaddr_old)==0 &&
		   ((rhost == NULL && rhost_old[0]=='\0') ||
		    (rhost && (strcmp(rhost, "*") == 0) && rhost_old[0]=='\0') ||
		    (rhost && (strcmp(rhost, rhost_old) == 0)))) {
			syslog(LOG_INFO, "updating existing port mapping %hu %s (rhost '%s') => %s:%hu",
				eport, protocol, rhost_old, iaddr_old, iport_old);
			timestamp = (leaseduration > 0) ? time(NULL) + leaseduration : 0;
			if(iport != iport_old) {
				r = update_portmapping(ext_if_name, eport, proto, iport, desc, timestamp);
			} else {
				r = update_portmapping_desc_timestamp(ext_if_name, eport, proto, desc, timestamp);
			}
#ifdef ENABLE_LEASEFILE
			if(r == 0) {
				lease_file_remove(eport, proto);
				lease_file_add(eport, iaddr, iport, proto, desc, timestamp);
			}
#endif /* ENABLE_LEASEFILE */
			return r;
		} else {
			syslog(LOG_INFO, "port %hu %s (rhost '%s') already redirected to %s:%hu",
				eport, protocol, rhost_old, iaddr_old, iport_old);
			return -2;
		}
#ifdef CHECK_PORTINUSE
	} else if (port_in_use(ext_if_name, eport, proto, iaddr, iport) > 0) {
		syslog(LOG_INFO, "port %hu protocol %s already in use",
		       eport, protocol);
		return -4;
#endif /* CHECK_PORTINUSE */
	} else {
		timestamp = (leaseduration > 0) ? time(NULL) + leaseduration : 0;
		syslog(LOG_INFO, "redirecting port %hu to %s:%hu protocol %s for: %s",
			eport, iaddr, iport, protocol, desc);
		return upnp_redirect_internal(rhost, eport, iaddr, iport, proto,
		                              desc, timestamp);
	}
}
Пример #9
0
int
upnp_delete_redirection(unsigned short eport, const char * protocol)
{
    NP_UPNP_DEBUG("removing redirect rule port %hu %s\n", eport, protocol);
    return _upnp_delete_redir(eport, proto_atoi(protocol));
}
Пример #10
0
/* upnp_redirect() 
 * calls OS/fw dependant implementation of the redirection.
 * protocol should be the string "TCP" or "UDP"
 * returns: 0 on success
 *          -1 failed to redirect
 *          -2 already redirected
 *          -3 permission check failed
 */
int
upnp_redirect(const char * rhost, unsigned short eport, 
              const char * iaddr, unsigned short iport,
              const char * protocol, const char * desc,
              unsigned int leaseduration, int enabled)
{
    int proto, r;
    int rr = 0;
    char iaddr_old[32];
    int enabled_old;
    unsigned short iport_old;
    struct in_addr address;
    unsigned int timestamp;
    NP_UPNP_DEBUG("enter upnp_redirect, enabled arg is %d\n", enabled);

    proto = proto_atoi(protocol);
    if(inet_aton(iaddr, &address) < 0) {
        NP_UPNP_ERROR("inet_aton(%s) : %s\n", iaddr, strerror(errno));
        return -1;
    }

    if(!check_upnp_rule_against_permissions(upnppermlist, num_upnpperm,
                                            eport, address, iport)) {
        NP_UPNP_DEBUG("redirection permission check failed for "
                         "%hu->%s:%hu %s\n", eport, iaddr, iport, protocol);
        return -3;
    }
    enabled_old = enabled;
    r = get_redirect_rule(ext_if_name, eport, proto,
                          iaddr_old, sizeof(iaddr_old), &iport_old, 0, 0,
                          0, 0,
                          &timestamp, 0, 0, &enabled_old);
    if(r == 0) {
        /* if existing redirect rule matches redirect request return success
         * xbox 360 does not keep track of the port it redirects and will
         * redirect another port when receiving ConflictInMappingEntry */
        if(strcmp(iaddr, iaddr_old)==0 && iport==iport_old)
        {
            if(enabled_old != enabled)
            {
                reload_port_mapping_rules();
            }
            else
            {
                NP_UPNP_DEBUG("ignoring redirect request as it matches existing redirect\n");
            }

        } else {

            NP_UPNP_DEBUG("port %hu protocol %s already redirected to %s:%hu\n",
                eport, protocol, iaddr_old, iport_old);
            
            /* 删除已存在的规则 */
            upnp_delete_redirection(eport, protocol);

            /* 重新添加规则 */
            timestamp = (leaseduration > 0) ? time(NULL) + leaseduration : 0;
            NP_UPNP_DEBUG("redirecting port %hu to %s:%hu protocol %s for: %s\n",
                eport, iaddr, iport, protocol, desc);           
            rr = upnp_redirect_internal(rhost, eport, iaddr, iport, proto,
                                          desc, timestamp, enabled);
            NP_UPNP_DEBUG("upnp_redirect_internal(...) returns %d\n", rr);
            return rr;
        }
    } else {
        timestamp = (leaseduration > 0) ? time(NULL) + leaseduration : 0;
        NP_UPNP_DEBUG("redirecting port %hu to %s:%hu protocol %s for: %s\n",
            eport, iaddr, iport, protocol, desc);           
        rr = upnp_redirect_internal(rhost, eport, iaddr, iport, proto,
                                      desc, timestamp, enabled);
        NP_UPNP_DEBUG("upnp_redirect_internal(...) returns %d\n", rr);
        return rr;
    }

    return 0;
}
Пример #11
0
/* upnp_redirect()
 * calls OS/fw dependant implementation of the redirection.
 * protocol should be the string "TCP" or "UDP"
 * returns: 0 on success
 *          -1 failed to redirect
 *          -2 already redirected
 *          -3 permission check failed
 */
int
upnp_redirect(unsigned short eport,
              const char * iaddr, unsigned short iport,
              const char * protocol, const char * desc)
{
    int proto, r;
    char iaddr_old[32];
    unsigned short iport_old;
    struct in_addr address;
    proto = proto_atoi(protocol);
    if(inet_aton(iaddr, &address) < 0)
    {
        syslog(LOG_ERR, "inet_aton(%s) : %m", iaddr);
        return -1;
    }

    if(!check_upnp_rule_against_permissions(upnppermlist, num_upnpperm,
                                            eport, address, iport))
    {
        syslog(LOG_INFO, "redirection permission check failed for "
               "%hu->%s:%hu %s", eport, iaddr, iport, protocol);
        return -3;
    }
    r = get_redirect_rule(ext_if_name, eport, proto,
                          iaddr_old, sizeof(iaddr_old), &iport_old, 0, 0, 0, 0);
    if(r == 0)
    {
        /* if existing redirect rule matches redirect request return success
         * xbox 360 does not keep track of the port it redirects and will
         * redirect another port when receiving ConflictInMappingEntry */
        if(strcmp(iaddr,iaddr_old)==0 && iport==iport_old)
        {
            syslog(LOG_INFO, "ignoring redirect request as it matches existing redirect");
        }
        else
        {

            syslog(LOG_INFO, "port %hu protocol %s already redirected to %s:%hu",
                   eport, protocol, iaddr_old, iport_old);
            return -2;
        }
    }
    else
    {
        syslog(LOG_INFO, "redirecting port %hu to %s:%hu protocol %s for: %s",
               eport, iaddr, iport, protocol, desc);
        return upnp_redirect_internal(eport, iaddr, iport, proto, desc);
#if 0
        if(add_redirect_rule2(ext_if_name, eport, iaddr, iport, proto, desc) < 0)
        {
            return -1;
        }

        syslog(LOG_INFO, "creating pass rule to %s:%hu protocol %s for: %s",
               iaddr, iport, protocol, desc);
        if(add_filter_rule2(ext_if_name, iaddr, eport, iport, proto, desc) < 0)
        {
            /* clean up the redirect rule */
#if !defined(__linux__)
            delete_redirect_rule(ext_if_name, eport, proto);
#endif
            return -1;
        }
#endif
    }

    return 0;
}