Пример #1
0
int main(int argc, char * * argv)
{
#ifndef CHECK_PORTINUSE
	UNUSED(argc); UNUSED(argv);
	printf("CHECK_PORTINUSE is not defined.\n");
#else /* CHECK_PORTINUSE */
	int r;
	const char * if_name;
	unsigned eport;
	int proto;
	const char * iaddr;
	unsigned iport;

	if(argc <= 5) {
		fprintf(stderr, "usage:   %s if_name eport (tcp|udp) iaddr iport\n",
		        argv[0]);
		return 1;
	}
	openlog("testportinuse",  LOG_CONS|LOG_PERROR, LOG_USER);
	if_name = argv[1];
	eport = (unsigned)atoi(argv[2]);
	proto = (0==strcmp(argv[3], "tcp"))?IPPROTO_TCP:IPPROTO_UDP;
	iaddr = argv[4];
	iport = (unsigned)atoi(argv[5]);
	
	r = port_in_use(if_name, eport, proto, iaddr, iport);
	printf("port_in_use(%s, %u, %d, %s, %u) returned %d\n",
	       if_name, eport, proto, iaddr, iport, r);
	closelog();
#endif /* CHECK_PORTINUSE */
	return 0;
}
Пример #2
0
int bmi_port_interface_add(bmi_port_mgr_t *port_mgr,
			   const char *ifname, int port_num,
			   const char *pcap_input_dump,
			   const char* pcap_output_dump)
{
  if(!port_num_valid(port_num)) return -1;

  bmi_port_t *port = get_port(port_mgr, port_num);
  if(port_in_use(port)) return -1;

  port->ifname = strdup(ifname);

  bmi_interface_t *bmi;
  if(bmi_interface_create(&bmi, ifname) != 0) return -1;

  if(pcap_input_dump) bmi_interface_add_dumper(bmi, pcap_input_dump, 1);
  if(pcap_output_dump) bmi_interface_add_dumper(bmi, pcap_output_dump, 0);

  pthread_mutex_lock(&port_mgr->lock);

  port->bmi = bmi;

  int fd = bmi_interface_get_fd(port->bmi);
  port->fd = fd;

  if(fd > port_mgr->max_fd) port_mgr->max_fd = fd;

  FD_SET(fd, &port_mgr->fds);

  pthread_mutex_unlock(&port_mgr->lock);

  return 0;
}
Пример #3
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);
}
Пример #4
0
int bmi_port_send(bmi_port_mgr_t *port_mgr,
		  int port_num, const char *buffer, int len) {
  if(!port_num_valid(port_num)) return -1;
  bmi_port_t *port = get_port(port_mgr, port_num);
  if(!port_in_use(port)) return -1;

  if(bmi_interface_send(port->bmi, buffer, len) != 0) return -1;

  return 0;
}
Пример #5
0
int bmi_port_destroy_mgr(bmi_port_mgr_t *port_mgr) {
  int i;
  for(i = 0; i < PORT_COUNT_MAX; i++) {
    bmi_port_t *port = get_port(port_mgr, i);
    if(port_in_use(port)) bmi_port_interface_remove(port_mgr, i);
  }

  port_mgr->max_fd = -1;  // used to signal the thread it needs to terminate

  pthread_join(port_mgr->select_thread, NULL);

  pthread_mutex_destroy(&port_mgr->lock);
      
  free(port_mgr);

  return 0;
}
Пример #6
0
int bmi_port_interface_remove(bmi_port_mgr_t *port_mgr, int port_num) {
  if(!port_num_valid(port_num)) return -1;

  bmi_port_t *port = get_port(port_mgr, port_num);
  if(!port_in_use(port)) return -1;

  free(port->ifname);

  pthread_mutex_lock(&port_mgr->lock);
  
  if(bmi_interface_destroy(port->bmi) != 0) return -1;

  FD_CLR(port->fd, &port_mgr->fds);

  memset(port, 0, sizeof(bmi_port_t));

  pthread_mutex_unlock(&port_mgr->lock);

  return 0;
}
Пример #7
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);
	}
}
Пример #8
0
/** read the request from the socket, process it and then send the
 * response back.
 */
void ProcessIncomingNATPMPPacket(int s, unsigned char *msg_buff, int len,
		struct sockaddr_in *senderaddr)
{
	unsigned char *req=msg_buff;	/* request udp packet */
	unsigned char resp[32];	/* response udp packet */
	int resplen;
	int n = len;
	char senderaddrstr[16];

	if(!inet_ntop(AF_INET, &senderaddr->sin_addr,
			senderaddrstr, sizeof(senderaddrstr))) {
		syslog(LOG_ERR, "inet_ntop(natpmp): %m");
	}

	syslog(LOG_INFO, "NAT-PMP request received from %s:%hu %dbytes",
	       senderaddrstr, ntohs(senderaddr->sin_port), n);

	if(n<2 || ((((req[1]-1)&~1)==0) && n<12)) {
		syslog(LOG_WARNING, "discarding NAT-PMP request (too short) %dBytes",
		       n);
		return;
	}
	if(req[1] & 128) {
		/* discarding NAT-PMP responses silently */
		return;
	}
	memset(resp, 0, sizeof(resp));
	resplen = 8;
	resp[1] = 128 + req[1];	/* response OPCODE is request OPCODE + 128 */
	/* setting response TIME STAMP :
	 * time elapsed since its port mapping table was initialized on
	 * startup or reset for any other reason */
	WRITENU32(resp+4, time(NULL) - startup_time);
	if(req[0] > 0) {
		/* invalid version */
		syslog(LOG_WARNING, "unsupported NAT-PMP version : %u",
		       (unsigned)req[0]);
		resp[3] = 1;	/* unsupported version */
	} else switch(req[1]) {
	case 0:	/* Public address request */
		syslog(LOG_INFO, "NAT-PMP public address request");
		FillPublicAddressResponse(resp, senderaddr->sin_addr.s_addr);
		resplen = 12;
		break;
	case 1:	/* UDP port mapping request */
	case 2:	/* TCP port mapping request */
		{
			unsigned short iport;	/* private port */
			unsigned short eport;	/* public port */
			uint32_t lifetime; 		/* lifetime=0 => remove port mapping */
			int r;
			int proto;
			char iaddr_old[16];
			unsigned short iport_old;
			unsigned int timestamp;

			iport = READNU16(req+4);
			eport = READNU16(req+6);
			lifetime = READNU32(req+8);
			proto = (req[1]==1)?IPPROTO_UDP:IPPROTO_TCP;
			syslog(LOG_INFO, "NAT-PMP port mapping request : "
			                 "%hu->%s:%hu %s lifetime=%us",
			                 eport, senderaddrstr, iport,
			                 (req[1]==1)?"udp":"tcp", lifetime);
			/* TODO: accept port mapping if iport ok but eport not ok
			 * (and set eport correctly) */
			if(lifetime == 0) {
				/* remove the mapping */
				/* RFC6886 :
				 * A client MAY also send an explicit packet to request deletion of a
				 * mapping that is no longer needed. A client requests explicit
				 * deletion of a mapping by sending a message to the NAT gateway
				 * requesting the mapping, with the Requested Lifetime in Seconds set to
				 * zero. The Suggested External Port MUST be set to zero by the client
				 * on sending, and MUST be ignored by the gateway on reception. */
				int index = 0;
				unsigned short eport2, iport2;
				char iaddr2[16];
				int proto2;
				char desc[64];
				eport = 0; /* to indicate correct removing of port mapping */
				while(get_redirect_rule_by_index(index, 0,
				          &eport2, iaddr2, sizeof(iaddr2),
						  &iport2, &proto2,
						  desc, sizeof(desc),
				          0, 0, &timestamp, 0, 0) >= 0) {
					syslog(LOG_DEBUG, "%d %d %hu->'%s':%hu '%s'",
					       index, proto2, eport2, iaddr2, iport2, desc);
					if(0 == strcmp(iaddr2, senderaddrstr)
					  && 0 == memcmp(desc, "NAT-PMP", 7)) {
						/* (iport == 0) => remove all the mappings for this client */
						if((iport == 0) || ((iport == iport2) && (proto == proto2))) {
							r = _upnp_delete_redir(eport2, proto2);
							if(r < 0) {
								syslog(LOG_ERR, "Failed to remove NAT-PMP mapping eport %hu, protocol %s",
								       eport2, (proto2==IPPROTO_TCP)?"TCP":"UDP");
								resp[3] = 2;	/* Not Authorized/Refused */
								break;
							} else {
								syslog(LOG_INFO, "NAT-PMP %s port %hu mapping removed",
								       proto2==IPPROTO_TCP?"TCP":"UDP", eport2);
								index--;
							}
						}
					}
					index++;
				}
			} else if(iport==0) {
				resp[3] = 2;	/* Not Authorized/Refused */
			} else { /* iport > 0 && lifetime > 0 */
				unsigned short eport_first = 0;
				int any_eport_allowed = 0;
				char desc[64];
				if(eport==0)	/* if no suggested external port, use same a internal port */
					eport = iport;
				while(resp[3] == 0) {
					if(eport_first == 0) { /* first time in loop */
						eport_first = eport;
					} else if(eport == eport_first) { /* no eport available */
						if(any_eport_allowed == 0) { /* all eports rejected by permissions */
							syslog(LOG_ERR, "No allowed eport for NAT-PMP %hu %s->%s:%hu",
							       eport, (proto==IPPROTO_TCP)?"tcp":"udp", senderaddrstr, iport);
							resp[3] = 2;	/* Not Authorized/Refused */
						} else { /* at least one eport allowed (but none available) */
							syslog(LOG_ERR, "Failed to find available eport for NAT-PMP %hu %s->%s:%hu",
							       eport, (proto==IPPROTO_TCP)?"tcp":"udp", senderaddrstr, iport);
							resp[3] = 4;	/* Out of resources */
						}
						break;
					}
					if(!check_upnp_rule_against_permissions(upnppermlist, num_upnpperm, eport, senderaddr->sin_addr, iport)) {
						eport++;
						if(eport == 0) eport++; /* skip port zero */
						continue;
					}
					any_eport_allowed = 1;	/* at lease one eport is allowed */
#ifdef CHECK_PORTINUSE
					if (port_in_use(ext_if_name, eport, proto, senderaddrstr, iport) > 0) {
						syslog(LOG_INFO, "port %hu protocol %s already in use",
						       eport, (proto==IPPROTO_TCP)?"tcp":"udp");
						eport++;
						if(eport == 0) eport++; /* skip port zero */
						continue;
					}
#endif
					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(strcmp(senderaddrstr, iaddr_old)==0
						    && iport==iport_old) {
							/* redirection already existing */
							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");
								break;
							}
						} else {
							eport++;
							if(eport == 0) eport++; /* skip port zero */
							continue;
						}
					}
					/* do the redirection */
#if 0
					timestamp = (unsigned)(time(NULL) - startup_time)
					                      + lifetime;
					snprintf(desc, sizeof(desc), "NAT-PMP %u", timestamp);
#else
					timestamp = time(NULL) + lifetime;
					snprintf(desc, sizeof(desc), "NAT-PMP %hu %s",
					         eport, (proto==IPPROTO_TCP)?"tcp":"udp");
#endif
					/* TODO : check return code */
					if(upnp_redirect_internal(NULL, eport, senderaddrstr,
					                          iport, proto, desc,
					                          timestamp) < 0) {
						syslog(LOG_ERR, "Failed to add NAT-PMP %hu %s->%s:%hu '%s'",
						       eport, (proto==IPPROTO_TCP)?"tcp":"udp", senderaddrstr, iport, desc);
						resp[3] = 3;  /* Failure */
					}
					break;
				}
			}
			WRITENU16(resp+8, iport);	/* private port */
			WRITENU16(resp+10, eport);	/* public port */
			WRITENU32(resp+12, lifetime);	/* Port Mapping lifetime */
		}
		resplen = 16;
		break;
	default:
		resp[3] = 5;	/* Unsupported OPCODE */
	}
	n = sendto_or_schedule(s, resp, resplen, 0,
	           (struct sockaddr *)senderaddr, sizeof(*senderaddr));
	if(n<0) {
		syslog(LOG_ERR, "sendto(natpmp): %m");
	} else if(n<resplen) {
		syslog(LOG_ERR, "sendto(natpmp): sent only %d bytes out of %d",
		       n, resplen);
	}
}