Beispiel #1
0
int main(int argc, char *argv[]) {
	struct hostent *hp;
	int flags;
	struct timeval tv;
	struct stun_state st;
        pthread_attr_t attr;
        pthread_t thread;

	gettimeofday(&tv, 0);
	srandom(tv.tv_sec + tv.tv_usec);

	hp=gethostbyname(argv[1]);
	memcpy(&stunserver.sin_addr, hp->h_addr, sizeof(stunserver.sin_addr));
	stunserver.sin_port = htons(3478);

	st.sock=socket(PF_INET,SOCK_DGRAM,0);
	flags = fcntl(st.sock, F_GETFL);
	fcntl(st.sock, F_SETFL, flags | O_NONBLOCK);

	st.bindaddr.sin_family=AF_INET;
	st.bindaddr.sin_addr.s_addr=inet_addr(argv[2]);
	st.bindaddr.sin_port=htons((random() % (65535-1023))+1023);
	bind(st.sock,(struct sockaddr *)&st.bindaddr,sizeof(struct sockaddr_in));

	pthread_attr_init(&attr);
	pthread_attr_setschedpolicy(&attr, SCHED_RR);
	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
	pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
	pthread_create(&thread, &attr, data_thread, &st);

	stun_send(STUN_BINDREQ,&st,NULL,0,0);

	while(1) {
		usleep(20000);
		gettimeofday(&tv,0);
		if ((tv.tv_sec*1000000+tv.tv_usec)-(st.laststun.tv_sec*1000000+st.laststun.tv_usec) > atoi(argv[3])*1000) {
			if ((st.result & STUN_NAT_SYMN) && (st.pcnt == 1)) {
				stun_send(STUN_BINDREQ,&st,NULL,0,2);
			} else {
				if (st.result < STUN_NAT_OPEN)
					printf("NEW IP:%s:%i Result: %i\n",inet_ntoa(st.bindaddr.sin_addr),ntohs(st.bindaddr.sin_port),st.result);
				else
					printf("NEW IP:%s:%i Result: %i\n",inet_ntoa(st.maddr.sin_addr),ntohs(st.maddr.sin_port),st.result);
				break;
			}
		}
	}
	pthread_attr_destroy(&attr);
	shutdown(st.sock,SHUT_RDWR);

	exit(0);
}
/**
 * Send a STUN response message
 *
 * @param proto   Transport Protocol
 * @param sock    Socket; UDP (struct udp_sock) or TCP (struct tcp_conn)
 * @param dst     Destination network address
 * @param presz   Number of bytes in preamble, if sending over TURN
 * @param req     Matching STUN request
 * @param key     Authentication key (optional)
 * @param keylen  Number of bytes in authentication key
 * @param fp      Use STUN Fingerprint attribute
 * @param attrc   Number of attributes to encode (variable arguments)
 * @param ...     Variable list of attribute-tuples
 *                Each attribute has 2 arguments, attribute type and value
 *
 * @return 0 if success, otherwise errorcode
 */
int stun_reply(int proto, void *sock, const struct sa *dst, size_t presz,
	       const struct stun_msg *req, const uint8_t *key,
	       size_t keylen, bool fp, uint32_t attrc, ...)
{
	struct mbuf *mb = NULL;
	int err = ENOMEM;
	va_list ap;

	if (!sock || !req)
		return EINVAL;

	mb = mbuf_alloc(256);
	if (!mb)
		goto out;

	va_start(ap, attrc);
	mb->pos = presz;
	err = stun_msg_vencode(mb, stun_msg_method(req),
			       STUN_CLASS_SUCCESS_RESP, stun_msg_tid(req),
			       NULL, key, keylen, fp, 0x00, attrc, ap);
	va_end(ap);
	if (err)
		goto out;

	mb->pos = presz;
	err = stun_send(proto, sock, dst, mb);

 out:
	mem_deref(mb);

	return err;
}
Beispiel #3
0
void ast_rtp_stun_request_peer(struct stun_state *st) {
	struct stun_attr *stunmsg=stun_message();
	int msglen=stun_attr_change(STUN_CHANGE_NONE,stunmsg,0);
	if (st->username) {
		msglen+=stun_attr_string(st->username, STUN_USERNAME, stunmsg, msglen);
	}
	stun_send(STUN_BINDREQ,st,stunmsg,msglen,0);
}
/**
 * Send a STUN error response
 *
 * @param proto   Transport Protocol
 * @param sock    Socket; UDP (struct udp_sock) or TCP (struct tcp_conn)
 * @param dst     Destination network address
 * @param presz   Number of bytes in preamble, if sending over TURN
 * @param req     Matching STUN request
 * @param scode   Status code
 * @param reason  Reason string
 * @param key     Authentication key (optional)
 * @param keylen  Number of bytes in authentication key
 * @param fp      Use STUN Fingerprint attribute
 * @param attrc   Number of attributes to encode (variable arguments)
 * @param ...     Variable list of attribute-tuples
 *                Each attribute has 2 arguments, attribute type and value
 *
 * @return 0 if success, otherwise errorcode
 */
int stun_ereply(int proto, void *sock, const struct sa *dst, size_t presz,
		const struct stun_msg *req, uint16_t scode,
		const char *reason, const uint8_t *key, size_t keylen,
		bool fp, uint32_t attrc, ...)
{
	struct stun_errcode ec;
	struct mbuf *mb = NULL;
	int err = ENOMEM;
	va_list ap;

	if (!sock || !req || !scode || !reason)
		return EINVAL;

	mb = mbuf_alloc(256);
	if (!mb)
		goto out;

	ec.code = scode;
	ec.reason = (char *)reason;

	va_start(ap, attrc);
	mb->pos = presz;
	err = stun_msg_vencode(mb, stun_msg_method(req), STUN_CLASS_ERROR_RESP,
			       stun_msg_tid(req), &ec, key, keylen,
			       fp, 0x00, attrc, ap);
	va_end(ap);
	if (err)
		goto out;

	mb->pos = presz;
	err = stun_send(proto, sock, dst, mb);

 out:
	mem_deref(mb);

	return err;
}
Beispiel #5
0
void stun_handle_packet(struct stun_state *st,struct sockaddr_in *src, void *buf, int len) {
	struct stun_header *hdr;
	unsigned char *data;
	int pcnt,msglen, option_debug=1,stundebug=1,msgtype;
	struct stun_attr *stunmsg;
	struct stun_attr *attr;
	struct sockaddr_in maddr,caddr;

	hdr=(struct stun_header *)buf;
	msgtype=ntohs(hdr->msgtype);

	if ((msgtype != STUN_BINDREQ) && (msgtype != STUN_BINDRESP)) {
		if (option_debug)
			printf("Dunno what to do with STUN message %04x (%s)\n", msgtype, stun_msg2str(msgtype));
		return;
	}

	if (len < sizeof(struct stun_header)) {
		if (option_debug)
			printf("Runt STUN packet (only %zd, wanting at least %zd)\n", len, sizeof(struct stun_header));
		return;
	}

	if (stundebug)
		printf("STUN Packet, msg %s (%04x), length: %d\n", stun_msg2str(ntohs(hdr->msgtype)), ntohs(hdr->msgtype), ntohs(hdr->msglen));

	if (ntohs(hdr->msglen) > len - sizeof(struct stun_header)) {
		printf("Scrambled STUN packet length (got %d, expecting %d)\n", ntohs(hdr->msglen), (int)(len - sizeof(struct stun_header)));
		return;
	} else {
		len = ntohs(hdr->msglen);
	}

	maddr=st->bindaddr;
	pcnt=hdr->id[3] & 0x000000FF;

	data = buf+sizeof(struct stun_header);


	if (len > 0) {
		while(len) {
			if (len < sizeof(struct stun_attr)) {
				if (option_debug)
					printf("Runt Attribute (got %zd, expecting %zd)\n", len, sizeof(struct stun_attr));
				break;
			}
			attr = (struct stun_attr*)data;
			if (ntohs(attr->len) > len) {
				if (option_debug)
					printf("Inconsistent Attribute (length %d exceeds remaining msg len %zd)\n", ntohs(attr->len), len);
				break;
			}
			switch (ntohs(attr->attr)) {
				case STUN_USERNAME:
					st->username=(char*)attr->value;
					break;
				case STUN_PASSWORD:
					st->password=(char*)attr->value;
					break;
				case STUN_MAPPED_ADDRESS:
					maddr=stun_addr_message((struct stun_addr*)attr->value);
					break;
				case STUN_CHANGED_ADDRESS:
					caddr=stun_addr_message((struct stun_addr*)attr->value);
					break;
				case STUN_CHANGE_REQUEST:
					printf("Change Request Sent Value %d\n",ntohl(*(long*)attr->value));
					break;
				default:
					if (stundebug)
						printf("Ignoring STUN attribute %s (%04x), length %d\n", stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr), ntohs(attr->len));
					if (option_debug)
						printf("Failed to handle attribute %s (%04x)\n", stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr));
					break;
			}
			data += ntohs(attr->len) + sizeof(struct stun_attr);
			len -= ntohs(attr->len) + sizeof(struct stun_attr);
		}
	} else {
		return;
	}
		

	switch (ntohs(hdr->msgtype)) {
		case STUN_BINDREQ:
			stunmsg=stun_message();
			msglen=0;
			if (st->username) {
				msglen=stun_attr_string(st->username, STUN_USERNAME, stunmsg, msglen);
			}
			msglen+=stun_attr_addr(src,STUN_MAPPED_ADDRESS, stunmsg, msglen);
			stun_send(STUN_BINDRESP,st,stunmsg,msglen,0);
			break;
		case STUN_BINDRESP:
			switch (pcnt) {
				case 0:
					st->maddr=maddr;
					st->caddr=caddr;
					st->result |= STUN_NAT_SYMN;
					if ((st->bindaddr.sin_addr.s_addr == maddr.sin_addr.s_addr) && (st->bindaddr.sin_port == maddr.sin_port))
						st->result |= STUN_NAT_SYMF;
					stunmsg=stun_message();
					msglen=stun_attr_change(STUN_CHANGE_PORT | STUN_CHANGE_IP,stunmsg,0);
					stun_send(STUN_BINDREQ,st,stunmsg,msglen,1);
					break;
				case 1:
					if (st->result & STUN_NAT_SYMF) {
						st->result |= STUN_NAT_OPEN;
					} else {
						st->result |= STUN_NAT_FULL;
					}
					break;
				case 2:
					if ((maddr.sin_addr.s_addr == st->maddr.sin_addr.s_addr) && (maddr.sin_port == st->maddr.sin_port))
						st->result |= STUN_NAT_PORT;
					stunmsg=stun_message();
					msglen=stun_attr_change(STUN_CHANGE_PORT,stunmsg,0);
					stun_send(STUN_BINDREQ,st,stunmsg,msglen,3);
					break;
				case 3:
					st->result |= STUN_NAT_RES;
					break;
			}
			st->pcnt++;
			break;
	}
	return;
}