Where is wrong with my STUN Binding request - stun

I send udp request to stun.l.google.com:19305, but I don't get any response from google stun server. I omit all of the error check in this piece of code. My program hang in recvfrom.
int stun_socket = socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in stun_client;
memset(&stun_client, 0, sizeof(stun_client));
stun_client.sin_family = AF_INET;
stun_client.sin_port = htons(local_port);
int rc = bind(stun_socket, (struct sockaddr *)&stun_client, sizeof(stun_client));
struct sockaddr_in stun_server;
memset(&stun_server, 0, sizeof(stun_server));
stun_server.sin_family = AF_INET;
stun_server.sin_port = htons(remote_port);
inet_pton(AF_INET, server, &stun_server.sin_addr);
typedef struct stun_header_tag {
uint16_t message_type;
uint16_t message_length;
unsigned char transaction_id[16];
} stun_header_t;
stun_header_t header;
header.message_type = htons(0x0001); /* Binding Request */
header.message_length = htons(0);
*(int *)(&header.transaction_id[8]) = 0xFFEEFFEE; /* transaction id in the response should keep consistent with this one */
rc = sendto(stun_socket, (void *)&header, sizeof(header), 0, (struct sockaddr *)&stun_server, sizeof(stun_server));
char response[64];
rc = recvfrom(stun_socket, response, 64, 0, NULL, 0);

I'm guessing you are doing something similar to this or equivalent for sending the data:
sendto(sock, &header, sizeof(header), (sockaddr*)&addr, addrlen);
If that's the case, you likely forgot to convert your message_type value to network byte order (big-endian).
Try this:
header.message_type = htons(0x0001);
But if you want a better solution, and you can use C++, use the client library built into Stuntman. You can generate a binding request as follows with the C++ class, CStunMessageBuilder, declared in the stuncore/stunbuilder.h file.
CStunMessageBuilder builder;
StunTransactionId transId;
builder.AddBindingRequestHeader();
builder.AddRandomTransactionId(&transID);
unsigned char* msg = builder.GetStream().GetDataPointerUnsafe();
size_t len = builder.GetStream().GetSize();
sendto(sock, msg, len, (sockaddr*)&addr, addrlen);

Related

recvfrom returning errno 14 in debug mode with GDB

I have a code something like this.
where recvfrom works fine if i run the code normally. but when i run the code with GDB, recvfrom doesn't wait for 2 seconds and instantly throwing errno 14.
==
char buf[sizeof(FSME_START)] = { 0 };
/* open socket */
fsm_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fsm_fd < 0)
{
perror("socket");
exit(1);
}
const struct sockaddr_in remote_addr = { .sin_family = AF_INET };
//socklen_t addrlen = sizeof(struct sockaddr);
socklen_t addrlen = sizeof(client_addr);
struct timeval tv = { .tv_sec = 2,
.tv_usec = 0};
/* set initial 1s recv timeout */
int ret = setsockopt(fsm_fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
if (ret < 0)
{
perror("setsockopt");
exit(1);
}
while (1)
{
const struct iovec iov = { .iov_base = (void*)FSME_START,
.iov_len = sizeof(FSME_START) };
// Send the START packet (once/sec) to the FSM-E until we get
// receive a START message back based on 1sec timeout set above.
fsm_dp_send(&iov,1,0);
ret = recvfrom(fsm_fd, (char *)buf, MAX_BUFSIZE,
MSG_WAITALL, (struct sockaddr *)&client_addr, &addrlen);
====
I tried passing client_addr and addrlen both parameters as NULL but no success. But strangely this code works if run without GDB.
Any suggestions
looks like there is an error with the size of msg i was passing with recvfrom but it was weird that one version of gdb and and even compiler was hiding this error. This error was visible only with older gdb version. Later on when i passed the correct size of the buffer, it was passing.

is there a working vmci example?

I need a working VMCI socket example that does what UDP does, but without networking. There are many good code fragments in the vmci_sockets.h code, but not a full working template to expand on.
I believe that the server should look as follows:
#include "vmci_sockets.h"
#define BUFSIZE 2048
int main() {
int afVMCI = VMCISock_GetAFValue();
if ((sockfd_dgram = socket(afVMCI, SOCK_DGRAM, 0)) == -1) {
perror("socket");
goto exit;
}
struct sockaddr_vm my_addr = {0};
my_addr.svm_family = afVMCI;
my_addr.svm_cid = VMADDR_CID_ANY;
my_addr.svm_port = VMADDR_PORT_ANY;
if (bind(sockfd, (struct sockaddr *) &my_addr, sizeof my_addr) == -1) {
perror("bind");
goto close;
}
if (getsockname(sockfd, (struct sockaddr *) &my_addr, &svm_size) == -1) {
perror("getsockname");
goto close;
}
if ((numbytes = recvfrom(sockfd, buf, sizeof buf, 0,
(struct sockaddr *) &their_addr, &svm_size)) == -1) {
perror("recvfrom");
goto close;
}
close:
return close(sockfd);
}
and for the client
#include <stdio.h>
#include <string.h>
#include "vmci_sockets.h"
#define BUFSIZE 128
int main() {
int afVMCI = VMCISock_GetAFValue();
int fd;
struct sockaddr_vm addr;
if ((fd = socket(afVMCI, SOCK_DGRAM, 0)) == -1) {
perror("socket");
return 1;
}
addr.svm_family = afVMCI;
addr.svm_cid = VMADDR_CID_ANY;
addr.svm_port = VMADDR_PORT_ANY;
bind(fd, (struct sockaddr *) &addr, sizeof addr);
struct sockaddr_vm serveraddr;
socklen_t svm_size = sizeof serveraddr;
{
int numbytes; char buf[BUFSIZE]; bzero(buf, BUFSIZE);
strcpy(buf, "hello there\n");
if ((numbytes = sendto(fd, buf, BUFSIZE, 0,
(const struct sockaddr *) &serveraddr, svm_size)) == -1) {
perror("sendto error");
goto close;
}
}
close:
close(fd);
VMCISock_ReleaseAFValueFd(fd);
return 0;
}
however, it's not working. there is not much documentation, e.g., how to troubleshoot. there is not information whether one can try both server and client within the same virtual machine for debugging purposes.
I tried to post to the vmware board, sent an email to their support, but no one seems to have a working example. because this is not standard socketry, though it is similar socketry, it is and is not followable.
anyone have a working example?
vmci is apparently not supported for vmplayer or vmware fusion. this is what the vmware support people told me:
I have been checking internally with our development team regarding
your request and incidentally could only generate interest if this was
a situation that is failing with vSphere. The final comment I have is
that we never meant to officially support this for VMware Fusion and
certain dependencies are on internal references only.
Unfortunately, we do not have any such vmci example which can be
shared publicly when it comes to VMware Fusion.

sendto() returning -1 in server

int main()
{
int servsocket,clientsocket;
struct sockaddr_in server,client;
FILE *file;
char filename[100];
char buf[1024];
servsocket=socket(AF_INET,SOCK_DGRAM,0);
server.sin_addr.s_addr=htonl(INADDR_ANY);
server.sin_port=htons(6003);
server.sin_family=AF_INET;
bind(servsocket,(struct sockaddr *) &server,sizeof(server) );
while(1){
int clientsize=0;
printf("Waiting for file requests \n");
recvfrom(servsocket,filename,sizeof(filename),0,(struct sockaddr *)&client,&clientsize);
file=fopen(filename,"r");
int size=0;
do
{
size=fread(buf,1,sizeof(buf),file);
printf("%d bytes read \n",size);
int sentbytes= sendto(servsocket,(const char *)buf,size,0, (struct sockaddr *) &client,sizeof(client));
printf("%d bytes sent ",sentbytes);
}while(size==sizeof(buf));
}
}
I am trying to make a simple program for file transfer using UDP. The problem is that sendto() always returns -1. This is the code for server.
There are quite a few issues with your code. The one you're seeing is that you're not filling in the variable client properly: the clientsize parameter is used for both input and output by the recvfrom system call, so you need to initialise it to the size of the client structure:
int clientsize = sizeof(struct sockaddr_in);
Another issue is that you're not 0-terminating the filename string:
n = recvfrom(...);
filename[n] = '\0';
Finally, you're not testing for errors (bind, recvfrom, sendto, etc.). This will get you into trouble, I promise.

why does my connect fail?

I am trying to do basic socket calls, and trying to connect to google.com but the connect call always fails and returns -1. Any reason why it must be failing
int main()
{
int sockfd;
struct addrinfo *ai;
char port[4];
if(sockfd = socket(AF_INET, SOCK_STREAM, 0) < 0) {
printf("socket return -1");
}
sprintf(port, "%d", 80);
if(getaddrinfo("www.google.com", port, NULL, &ai) < 0)
printf("-2\n");
if(connect(sockfd, ai->ai_addr, sizeof(*ai->ai_addr)) < 0)
printf("connect failed -1");
}
I believe the problem is with the parameter sizeof(*ai->ai_addr). ai->ai_addr returns a pointer to a sockaddr struct, and dereferencing brings you to the struct itself.
struct sockaddr {
unsigned short sa_family; // address family, AF_xxx
char sa_data[14]; // 14 bytes of protocol address
};
sizeof is returning the size of the entire struct, not the length of the address.
Try making the argument ai->ai_addrlen instead.

IPv6 raw socket programming with native C

I am working on IPv6 and need to craft an IPv6 packet from scratch and put it into a buffer. Unfortunately I do not have much experience with C. From a tutorial I have successfully done the same thing with IPv4 by defining
struct ipheader {
unsigned char iph_ihl:5, /* Little-endian */
iph_ver:4;
unsigned char iph_tos;
unsigned short int iph_len;
unsigned short int iph_ident;
unsigned char iph_flags;
unsigned short int iph_offset;
unsigned char iph_ttl;
unsigned char iph_protocol;
unsigned short int iph_chksum;
unsigned int iph_sourceip;
unsigned int iph_destip;
};
/* Structure of a TCP header */
struct tcpheader {
unsigned short int tcph_srcport;
unsigned short int tcph_destport;
unsigned int tcph_seqnum;
unsigned int tcph_acknum;
unsigned char tcph_reserved:4, tcph_offset:4;
// unsigned char tcph_flags;
unsigned int
tcp_res1:4, /*little-endian*/
tcph_hlen:4, /*length of tcp header in 32-bit words*/
tcph_fin:1, /*Finish flag "fin"*/
tcph_syn:1, /*Synchronize sequence numbers to start a connection*/
tcph_rst:1, /*Reset flag */
tcph_psh:1, /*Push, sends data to the application*/
tcph_ack:1, /*acknowledge*/
tcph_urg:1, /*urgent pointer*/
tcph_res2:2;
unsigned short int tcph_win;
unsigned short int tcph_chksum;
unsigned short int tcph_urgptr;
};
and fill the packet content in like this:
// IP structure
ip->iph_ihl = 5;
ip->iph_ver = 6;
ip->iph_tos = 16;
ip->iph_len = sizeof (struct ipheader) + sizeof (struct tcpheader);
ip->iph_ident = htons(54321);
ip->iph_offset = 0;
ip->iph_ttl = 64;
ip->iph_protocol = 6; // TCP
ip->iph_chksum = 0; // Done by kernel
// Source IP, modify as needed, spoofed, we accept through command line argument
ip->iph_sourceip = inet_addr("1922.168.1.128");
// Destination IP, modify as needed, but here we accept through command line argument
ip->iph_destip = inet_addr(1922.168.1.1);
// The TCP structure. The source port, spoofed, we accept through the command line
tcp->tcph_srcport = htons(atoi("1024"));
// The destination port, we accept through command line
tcp->tcph_destport = htons(atoi("4201"));
tcp->tcph_seqnum = htons(1);
tcp->tcph_acknum = 0;
tcp->tcph_offset = 5;
tcp->tcph_syn = 1;
tcp->tcph_ack = 0;
tcp->tcph_win = htons(32767);
tcp->tcph_chksum = 0; // Done by kernel
tcp->tcph_urgptr = 0;
// IP checksum calculation
ip->iph_chksum = csum((unsigned short *) buffer, (sizeof (struct ipheader) + sizeof (struct tcpheader)));
However for IPv6 I have not find a similar way. What I already found is this struct from IETF,
struct ip6_hdr {
union {
struct ip6_hdrctl {
uint32_t ip6_un1_flow; /* 4 bits version, 8 bits TC, 20 bits
flow-ID */
uint16_t ip6_un1_plen; /* payload length */
uint8_t ip6_un1_nxt; /* next header */
uint8_t ip6_un1_hlim; /* hop limit */
} ip6_un1;
uint8_t ip6_un2_vfc; /* 4 bits version, top 4 bits
tclass */
} ip6_ctlun;
struct in6_addr ip6_src; /* source address */
struct in6_addr ip6_dst; /* destination address */
};
But I did not know how to fill in the information, for example, how to send a TCP/SYN from 2001:220:806:22:aacc:ff:fe00:1 port 1024 to 2001:220:806:21::4 port 1025?
Could anybody help me or is there any references?
Thank you vere much then.
this is what I have done so far, however there are mismatch between the code and the real packet captured by Wireshark (as discussed in comments below). I'm not sure it is possible to post a long code in comment section, so I just edit my question.
Anyone can help?
#define PCKT_LEN 2000
int main(void) {
unsigned char buffer[PCKT_LEN];
int s;
struct sockaddr_in6 din;
struct ipv6_header *ip = (struct ipv6_header *) buffer;
struct tcpheader *tcp = (struct tcpheader *) (buffer + sizeof (struct ipv6_header));
memset(buffer, 0, PCKT_LEN);
din.sin6_family = AF_INET6;
din.sin6_port = htons(0);
inet_pton(AF_INET6, "::1", &(din.sin6_addr)); // For routing
ip->version = 6;
ip->traffic_class = 0;
ip->flow_label = 0;
ip->length = 40;
ip->next_header = 6;
ip->hop_limit = 64;
inet_pton(AF_INET6, "::1", &(ip->dst)); // IPv6
inet_pton(AF_INET6, "::1", &(ip->src)); // IPv6
tcp->tcph_srcport = htons(atoi("11111"));
tcp->tcph_destport = htons(atoi("13"));
tcp->tcph_seqnum = htons(0);
tcp->tcph_acknum = 0;
tcp->tcph_offset = 5;
tcp->tcph_syn = 1;
tcp->tcph_ack = 0;
tcp->tcph_win = htons(32752);
tcp->tcph_chksum = 0; // Done by kernel
tcp->tcph_urgptr = 0;
s = socket(PF_INET6, SOCK_RAW, IPPROTO_RAW);
if (s < 0) {
perror("socket()");
return 1;
}
unsigned short int packet_len = sizeof (struct ipv6_header) + sizeof (struct tcpheader);
if (sendto(s, buffer, packet_len, 0, (struct sockaddr*) &din, sizeof (din)) == -1) {
perror("sendto()");
close(s);
return 1;
}
close(s);
return 0;
}
Maybe this article can help you getting started?
Edit:
Using the wikipedia article linked above I made this structure (without knowing what some of the fields means):
struct ipv6_header
{
unsigned int
version : 4,
traffic_class : 8,
flow_label : 20;
uint16_t length;
uint8_t next_header;
uint8_t hop_limit;
struct in6_addr src;
struct in6_addr dst;
};
It's no different than how the header-struct was made for IPv4 in your example. Just create a struct containing the fields, in the right order and in the right size, and fill it with the right values.
Just do the same for the TCP headers.
Unfortunately the ipv6 RFCs don't provide the same raw socket interface that you get with ipv4. From what i've seen to create ipv6 packets you have to go a level deeper and use an AF_PACKET socket to send an ethernet frame including your ipv6 packet.