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; }
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; }
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; }