I was trying to send a TCP SYN packet to a server on my machine on port 8000. Then, I wanted to check if the server responded with a SYN ACK. If this was the case, then I would send back a RST packet to abort the connection. However, when I sniff the SYN packet that I send out it tells me the TCP header has a bogus length of 0, which isn't the case. The sniffer I used was tshark, by the way. Here's my code:
In the main function, I run this:
FLAGS f = SYN;
tcp_scan("127.0.0.1",8000,f,0);
This function assembles the IP header:
struct iphdr* assemble_ip(char* dest,unsigned int proto) {
/* Assemble IP Layer */
struct iphdr* iph;
iph = malloc(sizeof(struct iphdr)); // allocate memory
if (iph == NULL) { // if the ip header is NULL
err();
return NULL;
}
srand((unsigned int)time(NULL)); // seed random number generator
/* Hardcoded values */
iph->version = 4; // the version
iph->tos = 0; // type of services
iph->ihl = 5; // internet header length
iph->id = htons(rand() % 65536); // random id
iph->ttl = rand() % 257; // ttl
iph->frag_off = 0; // fragment offset
if (iph->ttl < 64) iph->ttl += 64; // if TTL is not sufficient
iph->tot_len = htons(iph->ihl*4); // the internet header length
/* User defined values */
iph->saddr = inet_addr(client); // source address
iph->daddr = inet_addr(dest); // destination address
iph->protocol = proto; // protocol
iph->check = 0; // set to zero for later calculation
return iph;
}
This function assembles the TCP header:
struct tcphdr* assemble_tcp(unsigned int sport,unsigned int dport,FLAGS f) {
/* Assemble TCP layer */
struct tcphdr* tcph;
tcph = malloc(sizeof(struct tcphdr)); // allocate tcp header
if (tcph == NULL) { // if tcp is NULL
err();
return NULL;
}
bzero(tcph,sizeof(struct tcphdr));
srand((unsigned int)time(NULL)); // seed random number generator
/* Hardcoded values */
tcph->seq = htonl(rand() % 65001); // generate random sequence number
tcph->ack_seq = 0; // ack sequence should be 0
tcph->doff = 5; // set data offset
tcph->window = htons(rand() % 65536); // set window size
/* Increase values by random value above 64 */
if (ntohs(tcph->seq) < 64) tcph->seq += (rand() % 101 + 64);
if (ntohs(tcph->window) < 64) tcph->window += (rand() % 101 + 64);
/* User-defined values */
tcph->source = htons(sport); // source port
tcph->dest = htons(dport); // destination port
tcph = set_flags(tcph,f); // set the TCP flags
/* Set urgent ptr if URG flag is set*/
if (tcph->urg == 1) tcph->urg_ptr = 1;
else tcph->urg_ptr = 0;
tcph->check = 0; // set the checksum to 0 for other calculations
return tcph;
}
Also, I do compute the checksum of the headers. For my purposes, when calculating the checksum, the IP header is always 20 bytes long, since I'm not sending any data or options. That means that there are 10 16-bit words in the header. The TCP header is also going to be 20 bytes long since I didn't add any options or data. Here's the code:
unsigned short ip_checksum(struct iphdr* iph) {
/* Acquire IP checksum */
/*
Checksum for Internet Protocol:
One's complement of the one's complement sum of the 16 bit words in the header.
So we get the first 16 bits of the header then add it to the sum, and then
we get the next 16 bits, and add it, and so on.
...0100101010110101 -> "..." represents more bits
1111111111111111 -> this is 131071 in base 10
0000100101010110101 -> notice how the "..." bits are now 0's
*/
/* One's complement sum */
unsigned long long* ptr;
unsigned long long hdr;
unsigned short sum = 0;
unsigned long mask = 131071;
ptr = (unsigned long long*)iph; // cast structure
hdr = *ptr; // get hdr
for (int i = 0; i < 10; i++) { // 20 bytes -> 160 bits / 16 bits = 10 words
sum += (hdr & mask); // add to sum
hdr >>= 16; // shift the next 16 bits
}
sum = ~sum; // inverse
return sum;
}
TCP Checksum:
unsigned short tcp_checksum(struct tcphdr* tcph,struct iphdr* iph) {
/* Calculate TCP checksum */
struct pseudo_hdr* pseudo_hdr;
u_char* buffer;
u_char* segment;
u_char* pseudo_segment;
unsigned short sum = 0;
unsigned long mask = 131071;
unsigned long long* ptr;
unsigned long long hdr;
pseudo_hdr = malloc(sizeof(struct pseudo_hdr)); // allocate memory
buffer = malloc(32); // allocate for 32 bytes of information
if (pseudo_hdr == NULL || buffer == NULL) { // if memory wasn't allocated properly
err();
if (pseudo_hdr != NULL) free(pseudo_hdr);
if (buffer != NULL) free(buffer);
return 0;
}
pseudo_hdr->saddr = (unsigned long)iph->saddr; // we add the cast because the fields if of type u_int_32
pseudo_hdr->daddr = (unsigned long)iph->daddr; // same reason for adding the cast as above
memset(&pseudo_hdr->reserved,0,8); // set these 8 bits to 0
pseudo_hdr->proto = IPPROTO_TCP; // this will always be 6
pseudo_hdr->len = htons(tcph->doff*4); // length of tcp header
/* Place both headers into a buffer */
segment = (u_char*)tcph;
pseudo_segment = (u_char*)pseudo_hdr;
/* Concactenate */
strncat((char*)buffer,(char*)pseudo_segment,12); // first the pseudo header
strncat((char*)buffer,(char*)segment,20); // then the TCP segment
/* Calculate checksum just like IP checksum */
ptr = (unsigned long long*)buffer; // convert buffer
hdr = *ptr; // dereference for clarity in following clode
for (int i = 0; i < 16; i++) { // 32 bytes -> 256 bits / 16 bits = 16 words
sum += (hdr & mask); // apply mask to header and add to sum
hdr >>= 16; // shift the next 16 bits
}
sum = ~sum; // bitwise NOT operation
return sum;
};
Here's all of the functions I stated above put together:
int tcp_scan(char* ipaddr,unsigned int port,FLAGS f,unsigned int justsend) {
/* Do a TCP port scan */
u_char* buffer;
u_char recvbuf[65535];
u_char* ipbuf;
u_char* tcpbuf;
int s;
size_t bufsize;
size_t size;
struct sockaddr_in sa;
struct sockaddr_in recvstruct;
struct msghdr msg;
struct iovec iv[1];
struct iphdr* iph;
struct tcphdr* tcph;
FLAGS rst = RST;
srand((unsigned int)time(NULL)); // seed random number generator
bufsize = sizeof(struct tcphdr) + sizeof(struct iphdr); // store size in variable
buffer = malloc(bufsize); // allocate memory to buffer
iph = assemble_ip(ipaddr,IPPROTO_TCP); // set the ip address to provided and protocol as TCP
tcph = assemble_tcp(rand() % 65536,port,f); // set flag, source port as rand, and dest port as supplied port num
if (iph == NULL || tcph == NULL || buffer == NULL) { // if error occurs
err();
/* Deallocate memory to variables that still have it */
if (iph != NULL) free(iph);
if (tcph != NULL) free(tcph);
if (buffer != NULL) free(buffer);
return -1;
}
/* Now compute checksum */
iph->check = htons(ip_checksum(iph));
tcph->check = htons(tcp_checksum(tcph,iph));
/* Store headers in buffer */
ipbuf = (u_char*)iph;
tcpbuf = (u_char*)tcph;
/* Concactenate to buffer */
strncat((char*)buffer,(char*)tcpbuf,20); // copy only 20 bytes...this ensures that no extra bytes are catted
strncat((char*)buffer,(char*)ipbuf,20); // do same thing but with ip header
/* Create a socket */
s = create_socket(); // create a raw socket
if (s == -1) return -1; // if the socket wasn't able to be created
/* Clear memory */
bzero(&sa,sizeof(struct sockaddr_in));
bzero(&recvstruct,sizeof(struct sockaddr_in));
bzero(&msg,sizeof(struct msghdr));
bzero(&iv,sizeof(struct iovec));
/* For analyze_packet() */
sa.sin_family = AF_INET; // address family
sa.sin_addr.s_addr = inet_addr(ipaddr); // convert ip address
sa.sin_port = htons(port); // port number
/* For sendmsg() */
iv[0].iov_base = buffer;
iv[0].iov_len = bufsize;
msg.msg_name = &sa; // caller allocated buffer
msg.msg_namelen = sizeof(struct sockaddr_in); // specify size of buffer
msg.msg_iov = iv; // iov structure array
msg.msg_iovlen = 1; // the length of the array
msg.msg_control = NULL; // for ancillary data
msg.msg_controllen = 0; // sizeof ancillary data
if (sendmsg(s,&msg,0) == -1) {
err();
return -1;
}
printf("Sent\n");
if (justsend) return 0; // exit cleanly
bzero(&recvstruct,sizeof(struct sockaddr_in)); // clear structure
size = sizeof(struct sockaddr_in); // acquire size of recv structure
for(int i = 0; i < 100; i++) { // loop until we've received 100 packets
printf("Receiving\n");
bzero(recvbuf,65535); // clear memory
if (recvfrom(s,recvbuf,sizeof(recvbuf),0,(struct sockaddr*)&recvstruct,(socklen_t*)&size) == -1) { // recv
err();
return -1;
}
if (analyze_packet(recvbuf,sa,recvstruct) == 0) { // if packet is what we wanted
printf("\ttcp %d is open\n",port); // print out that port is opened
tcp_scan(ipaddr,port,rst,-1); // abort connection with RST flag
break;
}
}
return 0;
}
Alright, now that you've seen those, here's the 'tshark' command I used to sniff the packets:
sudo tshark -o tcp.check_checksum:TRUE # I also wanted to check the checksum value to make sure it was OK
Now here's the command to run the program:
sudo ./netmap enp0s3 # enp0s3 is the interface I'm sending packets on
After running both of these in separate terminals, tshark provides this output:
1 0.000000 10.0.2.15 -> 127.0.0.1 TCP 74 31280->8000 [<None>] Seq=1 Win=0, bogus TCP header length (0, must be 20)
Please note that the declarations for struct iphdr and struct tcphdr are located in the system header files <netinet/ip.h> and <netinet/tcp.h>, respectively.
I'm really lost as to how to solve this issue. In fact, I'm not certain what is causing the issue, in the first place. According to my knowledge there's no way to specify the length of the TCP header. Any help would be appreciated.
I think your problem is here
strncat((char*)buffer,(char*)tcpbuf,20); // copy only 20 bytes...this ensures that no extra bytes are catted
strncat((char*)buffer,(char*)ipbuf,20);
The headers aren't strings so you may only be copying part of each header. Try something like this;
memcpy((char*)buffer, (char*)tcpbuf, 20);
memcpy((char*)buffer+20, (char*)ipbuf, 20);
Related
Hello i created Network driver that uses the uart port to send and recive.
My driver works with some issues. I was able to ping but always afther a few pings i get
ping: sendmsg: No buffer space available driver
I checked the kernel logs but i could not see anything.
this is how i recive data:
struct stm32_port *stm32_port = netdev_priv(my_net);
struct sk_buff *skb;
unsigned char *dma_start;
dma_start = stm32_port->rx_buf + (RX_BUF_L - stm32_port->last_res);
print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_OFFSET, 16, 1, dma_start, 16, true);
skb = dev_alloc_skb(dma_size + 2);
if (!skb) {
if (printk_ratelimit( ))
printk(KERN_NOTICE "snull rx: low on mem - packet dropped\n");
my_net->stats.rx_dropped++;
//goto error;
}
memcpy(skb_put(skb, dma_size), dma_start, dma_size);
/* Write metadata, and then pass to the receive level */
skb->dev = my_net;
skb->protocol = eth_type_trans(skb, my_net);
skb->ip_summed = CHECKSUM_NONE; // let the OS check the checksum
my_net->stats.rx_packets++;
my_net->stats.rx_bytes += dma_size;
netif_rx(skb);
port->icount.rx += dma_size;
stm32_port->last_res -= dma_size;
if (stm32_port->last_res == 0)
stm32_port->last_res = RX_BUF_L; //dma_count
Here is how i send my data:
struct stm32_port *lp = netdev_priv(ndev);
struct uart_port *port = &lp->port;
struct sk_buff *sk_buff;
struct dma_async_tx_descriptor *desc = NULL;
struct stm32_usart_offsets *ofs = &lp->info->ofs;
unsigned pktlen = skb->len;
dma_cookie_t cookie;
int ret = 0;
//print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_OFFSET, 16, 1, skb->data, 16, true);
netif_stop_queue(ndev);
sk_buff = skb_get(skb);
if (ofs->icr == UNDEF_REG){
stm32_usart_clr_bits(port, ofs->isr, USART_SR_TC);
}else{
writel_relaxed(USART_ICR_TCCF, port->membase + ofs->icr);
}
memcpy(&lp->tx_buf[0], sk_buff->data, pktlen);
desc = dmaengine_prep_slave_single(lp->tx_ch,
lp->tx_dma_buf,
pktlen,
DMA_MEM_TO_DEV,
DMA_PREP_INTERRUPT);
if (!desc){
goto fallback_err;
}
cookie = dmaengine_submit(desc);
ret = dma_submit_error(cookie);
if (ret) {
/* dma no yet started, safe to free resources */
dmaengine_terminate_async(lp->tx_ch);
goto fallback_err;
}
/* Issue pending DMA TX requests */
dma_async_issue_pending(lp->tx_ch);
stm32_usart_set_bits(port, ofs->cr3, USART_CR3_DMAT);
/* rely on TXE irq (mask or unmask) for sending remaining data */
stm32_usart_tx_interrupt_disable(port);
ndev->stats.tx_packets++;
ndev->stats.tx_bytes += pktlen;
fallback_err:
skb_tx_timestamp(skb);
dev_kfree_skb (skb);
netif_start_queue(ndev);
return NETDEV_TX_OK;
Thanks to #stark i found a solution i free the buffer now with the __kfree_skb() methode because like that the refcount will not be checked.
I am trying to send a TCP SYN packet through a RAW socket in C (I know it's not the easiest thing to do but I have academic reasons to do so).
When I check the outgoing packet, every fields are good but one: the TCP checksum. Indeed, Wireshark tells me it is incorrect.
In the following code, you can see how I build the packet (the IP headers are omitted because they seem to be OK).
#define MINIMUM_TCP_HEADER_LENGTH 20
#define DEFAULT_TCP_WINDOW 32767
// [... Code that sets the IP headers ...]
struct tcphdr * tcpHeaders = (struct tcphdr *) (packetBuffer + IPHeaderLength);
tcpHeaders->source = htons(srcPort_16);
tcpHeaders->dest = htons(dstPort_16);
tcpHeaders->seq = htonl(tcpSeq_32);
tcpHeaders->ack_seq = 0;
tcpHeaders->doff = (MINIMUM_TCP_HEADER_LENGTH / 4);
tcpHeaders->res1 = 0;
tcpHeaders->res2 = 0;
tcpHeaders->syn = 1;
tcpHeaders->ack = 0;
tcpHeaders->fin = 0;
tcpHeaders->psh = 0;
tcpHeaders->urg = 0;
tcpHeaders->rst = 0;
tcpHeaders->window = htons(DEFAULT_TCP_WINDOW);
tcpHeaders->check = 0x0;
tcpHeaders->urg_ptr = 0x0;
//Sets the data
uint8_t * tcdData = ((uint8_t*) tcpHeaders + MINIMUM_TCP_HEADER_LENGTH);
memcpy(tcdData, message, strlen(message));
//Compute TCP checksum over the pseudo TCP header
uint8_t * pseudo = pseudoBuffer;
memset(pseudo, 0, DEFAULT_BUFFER_SIZE);
memcpy(pseudo, &((ipHeaders->ip_src).s_addr), 4);
pseudo += 4;
memcpy(pseudo, &((ipHeaders->ip_dst).s_addr), 4);
pseudo += 4;
memset(pseudo++, 0, 1);
memset(pseudo++, IPPROTO_TCP, 1);
uint16_t tcpSegmentLength = htons(MINIMUM_TCP_HEADER_LENGTH + (uint32_t) strlen(message));
memcpy(pseudo, &tcpSegmentLength, 2);
pseudo += 2;
//Append the TCP headers and data to the pseudo header
memcpy(pseudo, tcpHeaders, MINIMUM_TCP_HEADER_LENGTH + strlen(attentionMessage));
pseudo += MINIMUM_TCP_HEADER_LENGTH + strlen(attentionMessage);
//Compute checksum
int pseudoBufferLength = pseudo - pseudoBuffer;
tcpHeaders->check = calculateInternetChecksum((uint16_t*) pseudoBuffer, pseudoBufferLength);
//[... Code that proceed to send the packet ...]
It is worth noting that both "packetBuffer" have been filled with zeros using memset (just like "pseudo" is) and that the
"message" is a regular string.
Here is the function that computes the checksum:
uint16_t onesComplementAddition(uint16_t *buff, unsigned int nbytes) {
if(buff == 0 || nbytes == 0)
return 0;
uint32_t sum = 0;
for (; nbytes > 1; nbytes -= 2)
sum += *buff++;
if (nbytes == 1)
sum += *(uint8_t*) buff;
sum = (sum >> 16) + (sum & 0xFFFF);
sum += (sum >> 16);
return sum;
}
uint16_t calculateInternetChecksum(uint16_t *buff, unsigned int nbytes) {
return ~(onesComplementAddition(buff, nbytes));
}
Wireshark suggests that this could be caused by "TCP checksum offload" but
I doubt it as I don't receive any response from the machine I probe (even though I know for a fact that I should).
Does anyone have an idea why the TCP checksum is not correct?
Thanks in advance.
Sorry guys, it's one of those times when asking the question actually gives me the answer.
If I understood the documentation correctly, when using a RAW socket, the kernel will replace the IP source address with the address of the sending interface only if the "source" field is 0 (http://man7.org/linux/man-pages/man7/raw.7.html#DESCRIPTION).
As I was using that feature, I computed my checksum over a TCP pseudo header with an IP source that was 0. That could obviously not work.
Thanks if anyone tried to solve my issue.
I want to manually build a dns query to the dns sever using socket APIs (it's part of the project and can not be changed). So I want to copy a struct like:
typedef struct {
uint16_t dns_id; /* identification number */
uint16_t dns_flags; /* DNS flags */
uint16_t dns_qdc; /* number of question entries */
uint16_t dns_anc; /* number of answer entries */
uint16_t dns_nsc; /* number of authority entries */
uint16_t dns_arc; /* number of resource entries */
unsigned char *host;
unsigned short qtype;
unsigned short qclass;
} DNS_QUERY;
DNS_QUERY* dns_query = (DNS_QUERY *) malloc(sizeof(DNS_QUERY));
into a buffer like:
char* dns_buf = malloc(500);
but when I do that, nothing has been copied into the buffer. When I input different strings to the *host element, the sizeof(dns_query) stays the same. When I use
memcpy(dns_buf, dns_query, sizeof(DNS_QUERY));
it gives output like:
dns_buf:
strlen(dns_buf)= 0
Also when I print it using for loop like:
for (i = 0 ; i<strlen(dns_buf) ; i++){
printf("%c", dns_buf[i]);
}
it doesn't output anything
When I use pointers instead of memcpy, like:
dns_buf = dns_query;
it gives the same output. Could anybody instruct me on what I should do?
This is the whole code:
int udp_connect(char *hostname, char *dns_name, char buf[]){
int sockfd;
int num_bytes;
struct sockaddr_in servaddr;
char str[INET_ADDRSTRLEN];
struct hostent *hptr; /* For gethostbyname() */
char **pptr; /* For inet_ntop() */
char* dns_buf, recv_buf = NULL;
int len = 0;
int i = 0;
static unsigned short id = 0; /* For the query ID */
/* Allocating memory for structs */
DNS_QUERY* dns_query = malloc(sizeof(DNS_QUERY));
/* QUESTION *dns_question = malloc(sizeof(QUESTION));*/
recv_buf = malloc(MAXDATASIZE);
if((hptr = gethostbyname(dns_name)) == NULL){
perror("Error in gethostbyname()\n");
exit(1);
}
if ((pptr = hptr->h_addr_list) != NULL) { /* (hptr->h_addrtype == AF_INET) && */
printf("The address is: %s\n", inet_ntop(hptr->h_addrtype, *pptr, str, sizeof(str)));
} else {
perror("Error in inet_ntop() \n");
}
memset(&servaddr, 0, sizeof (servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(DNS_PORT);
inet_pton(AF_INET, str, &servaddr.sin_addr);
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1){
perror("Error while making a socket");
return -1;
}
/* Setting hostname into the name segment of the query */
ChangetoDnsNameFormat(hostname);
dns_query->host = hostname;
printf("\ndns_query->host: %s\n", dns_query->host);
/* memcpy(dns_buf, dns_query, sizeof(DNS_QUERY)); */
/* setting up the header */
dns_query->dns_id = htons(id); /* id */
dns_query->dns_flags = htons(0x10); /* 0000000100000000 recursion is desired*/
dns_query->dns_qdc = htons(0x01); /* We have one question */
dns_query->dns_anc = htons(0x00);
dns_query->dns_nsc = htons(0x00);
dns_query->dns_arc = htons(0x00);
dns_query->qtype = htons(1); /* For IPv4 */
dns_query->qclass = htons(1); /* For internet */
len = sizeof(DNS_QUERY) + strlen(hostname); /* Calculating the length to use it in sendto() */
dns_buf = malloc(len);
dns_buf = dns_query;
/* memcpy(dns_buf, dns_query, sizeof(DNS_QUERY)); */
for (i = 0 ; i<sizeof(DNS_QUERY) ; i++){
printf("%02X", dns_buf[i]);
}
/* to check if the same as dns_query, use the following print also */
for (i = 0 ; i<sizeof(DNS_QUERY) ; i++){
printf("%02X", dns_query[i]);
}
print("\n");
/* Sending the datagram to the dns server */
printf("\n--------------------\nSending datagram: \n%s\n", dns_buf);
if ((num_bytes = sendto(sockfd, dns_buf, len, 0, (struct sockaddr *) &servaddr, sizeof(servaddr))) == -1){
perror("Error in sendto");
exit(1);
}
/* Receiving the datagram from the dns server */
printf("Receiving datagram...\n");
num_bytes = recvfrom(sockfd, recv_buf, MAXDATASIZE, 0, NULL, NULL);
printf("Received %i bytes of datagram...\n", num_bytes);
printf("dns_buf in udp connect: %s\n", recv_buf);
id = id + 1;
free(dns_query);
freeaddrinfo((struct addrinfo *) &servaddr);
close(sockfd);
return sockfd;
}
/******************************************************************************/
void ChangetoDnsNameFormat(char *hostname)
{
int walker=0;
int i;
int counter = 0;
char tmp[40];
strcat(hostname, "$"); /* For having a $ at the end of the dns name format */
for(i=0 ; i< (int) strlen((char*)hostname) ; i++)
{
if(hostname[i]=='.')
{
tmp[walker] = (char) counter + 48;
/*printf("%s\n", tmp);*/
for( ; walker < i ; walker++)
{
tmp[walker + 1] = hostname[walker];
}
walker++;
counter = -1;
}else if(hostname[i]=='$'){
tmp[walker] = (char) counter + 47;
/*printf("%s\n", tmp);*/
for( ; walker < i ; walker++)
{
tmp[walker + 1] = hostname[walker];
}
walker++;
counter = -1;
}
counter++;
}
walker--;
tmp[walker] = '\0'; /* Terminate the string */
strcat(tmp, "0"); /* For having a 0 at the end of the dns name format */
strcpy(hostname, tmp);
}
The struct doesn't really contain the array of character host but rather a pointer to the first element.
This means that, although you are copying the whole structure, you just copy the pointer to the data contained in host (which then points to the same string). What you shall do is something like:
DNS_QUERY *dns_buf = malloc(sizeof(DNS_QUERY));
memcpy(dns_buf, dns_query, sizeof(DNS_QUERY));
dns_buf.host = "yourmodifiedhost";
dns_buf is not a string (which finish with null charcter).
it's a pointer (as char *) to a memory space and the memory could contains 0 as values at the beginning so that's why when you use strlen(dns_buf) you get it = to 0 that means the fisrt element in the dns_buf is 0
to see the dns_buf content you can use:
for (i = 0 ; i<sizeof(DNS_QUERY) ; i++){
printf("%02X", dns_buf[i]);
}
print("\n");
// to check if the same as dns_query, use the following print also
for (i = 0 ; i<sizeof(DNS_QUERY) ; i++){
printf("%02X", dns_query[i]);
}
print("\n");
I have written a program to set the MTU size of the particular interface(say eth0 or eth1) to 1100. And the Request message is send from user space using Netlink sockets via NETLINK_ROUTE option.
The message is sent successfully from user space, but when i verified the ifconfig eth0, the MTU size still shows the old value (1500). Am I verifying correctly? And how do I know the kernel is setting the MTU size correctly or not? Please find my program below and correct me if i am wrong.
#include <stdio.h>
#include <stdlib.h>
#include <net/if.h>
#include <string.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <stdbool.h>
struct {
struct nlmsghdr nh;
struct ifinfomsg ifinfo;
char data[100];
}req;
int ret;
struct rtattr *rta;
/* MTU Set */
unsigned int mtu = 1100;
/* rtNetlinkSockFd */
int rtNetlinkSockFd = -1;
int main()
{
int ret;
rtNetlinkSockFd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
if(rtNetlinkSockFd < 0)
{
printf("Creation of NetLink Socket is failed \n");
return -1;
}
/* Memset the Requested Structure */
memset( &req, 0x00, sizeof(req));
/* Populate the Netlink Header Fields */
req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
/* Link Layer: RTM_NEWLINK, RTM_DELLINK, RTM_GETLINK, RTM_SETLINK */
req.nh.nlmsg_type = RTM_SETLINK;
/* NLM_F_REQUEST Must be set on all request messages. */
req.nh.nlmsg_flags = NLM_F_REQUEST;
req.nh.nlmsg_seq = 0;
req.nh.nlmsg_pid = 0; //getpid();
/* Populate the Ifinfo Structure Attributes */
req.ifinfo.ifi_family = AF_UNSPEC;
/* Give the Interface Name and get the Index */
req.ifinfo.ifi_index = if_nametoindex("eth0");
printf(" The NetLink Ifi_index :%d\n", req.ifinfo.ifi_index);
/* ifi_change is reserved for future use and
* should be always set to 0xFFFFFFFF. */
req.ifinfo.ifi_change = 0xFFFFFFFF;
req.ifinfo.ifi_type = 0;
req.ifinfo.ifi_flags = 0;
/* RTA is Pointed to (req+32) it means points to the DATA */
rta = (struct rtattr *)(((char *) &req) + NLMSG_ALIGN(req.nh.nlmsg_len));
/* IFLA_MTU unsigned int MTU of the device. */
rta->rta_type = IFLA_MTU;
/* Len Attribute */
rta->rta_len = sizeof(unsigned int);
req.nh.nlmsg_len = NLMSG_ALIGN(req.nh.nlmsg_len) + RTA_LENGTH(sizeof(mtu));
memcpy(RTA_DATA(rta), &mtu, sizeof(mtu));
ret = send(rtNetlinkSockFd, &req, req.nh.nlmsg_len, 0);
if (ret < 0)
{
printf( "netlink: Sending failed: (assume operstate is not supported)");
}
else
{
printf( "netlink: Sent successfully");
}
return 0;
}
I think you need to write:
rta->rta_len = RTA_LENGTH(sizeof(unsigned int));
instead of:
rta->rta_len = sizeof(unsigned int);
Use RTM_NEWLINK instead of RTM_SETLINK.
req.nh.nlmsg_type = RTM_NEWLINK;
See the manpage example.
I have a program which is FEC-encoding data, sending the data; receiving the data at another socket, and decoding the data.
I get an error when the sendto-function is executed in the code attached below. More information about the sendto-function here: Link
The return code of the error is '-1'.
What is the cause of this error and what should I change in the code in order to resolve it?
Print-outs from the 'receiver':
*** Sender -- socket created
***we have a client, and will sent message to server_addr ...server.. will receive messages.. sss
*** Created server socket good. Server socket is 4
***We have a server socket; and now we will try to bind it with the IP_ADDR-local host -- that we sent..
port nr 4783 & ip 127.0.0.1***Bind succeed..
Thread 1
Some lines of eperftool.h
#define PORT_NUM 4783 // Arbitrary port number for the server
#define IP_ADDR "127.0.0.1" // IP address of server1 (*** HARDWIRED ***)
#define SYMBOL_SIZE 1024 //todo..on a different position also
#define MAX_K 1000
#define MAX_N 1500
Code of sender.c:
/* $Id: sender.c 3 2011-03-03 10:48:54Z detchart $ */
/*
* OpenFEC.org AL-FEC Library.
* (c) Copyright 2009-2011 INRIA - All rights reserved
* Contact: vincent.roca#inria.fr
*
* This software is governed by the CeCILL-C license under French law and
* abiding by the rules of distribution of free software. You can use,
* modify and/ or redistribute the software under the terms of the CeCILL-C
* license as circulated by CEA, CNRS and INRIA at the following URL
* "http://www.cecill.info".
*
* As a counterpart to the access to the source code and rights to copy,
* modify and redistribute granted by the license, users are provided only
* with a limited warranty and the software's author, the holder of the
* economic rights, and the successive licensors have only limited
* liability.
*
* In this respect, the user's attention is drawn to the risks associated
* with loading, using, modifying and/or developing or reproducing the
* software by the user in light of its specific status of free software,
* that may mean that it is complicated to manipulate, and that also
* therefore means that it is reserved for developers and experienced
* professionals having in-depth computer knowledge. Users are therefore
* encouraged to load and test the software's suitability as regards their
* requirements in conditions enabling the security of their systems and/or
* data to be ensured and, more generally, to use and operate it in the
* same conditions as regards security.
*
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL-C license and that you accept its terms.
*/
/* AL-FEC extended performance evaluation tool */
#include "eperftool.h"
/*
* local variables
*/
static void **encoding_symbols_tab; /* temporary symbol array needed by the FEC encoder */
of_status_t
init_sender (void)
{
of_session_t *ses; /* pointer to a codec instance */
block_cb_t *blk; /* temporary pointer within the blk_cb_tab[] */
UINT32 sbn; /* block sequence number */
UINT32 k; /* k parameter for a given block. Warning, the last block might be shorter */
UINT32 n; /* n parameter for a given block. Warning, the last block might be shorter */
UINT32 esi; /* Encoding Symbol ID */
UINT32 src_idx; /* index for a source symbol in the orig_symb[] table */
UINT32 rep_idx; /* index for a repair symbol in the orig_symb[] table */
symbol_cb_t *src_symb_cb; /* pointer to a source symbol in the orig_symb[] table */
symbol_cb_t *rep_symb_cb; /* pointer to a repair symbol in the orig_symb[] table */
UINT32 tmp_max_k; /* temporary value for max_k */
UINT32 max_n_4_any_blk;/* maximum n value for any block */
#ifdef WIN32
QueryPerformanceCounter(&tv0);
OF_PRINT(("init_start=%lI64f\n", (double)tv0.QuadPart/(double)freq.QuadPart))
#else
gettimeofday(&tv0, NULL);
OF_PRINT(("init_start=%ld.%ld\n", tv0.tv_sec, tv0.tv_usec))
#endif
/*
* determine the blocking structure, which requires to create a temporary FEC session.
*/
if (of_create_codec_instance(&ses, codec_id, OF_ENCODER, of_verbosity) != OF_STATUS_OK) {
OF_PRINT_ERROR(("init_sender: ERROR: of_create_codec_instance() failed\n"))
goto error;
}
if (codec_id == OF_CODEC_REED_SOLOMON_GF_2_M_STABLE) {
if (of_set_control_parameter(ses, OF_RS_CTRL_SET_FIELD_SIZE, (void*)&rs_m_param, sizeof(rs_m_param)) != OF_STATUS_OK) {
OF_PRINT_ERROR(("init_sender: ERROR: of_set_control_parameter() failed\n"))
goto error;
}
}
if (of_get_control_parameter(ses, OF_CTRL_GET_MAX_K, (void*)&max_k, sizeof(max_k)) != OF_STATUS_OK) {
OF_PRINT_ERROR(("init_sender: ERROR: of_get_control_parameter() failed\n"))
goto error;
}
if (of_get_control_parameter(ses, OF_CTRL_GET_MAX_N, (void*)&max_n, sizeof(max_n)) != OF_STATUS_OK) {
OF_PRINT_ERROR(("init_sender: ERROR: of_get_control_parameter() failed\n"))
goto error;
}
if (of_release_codec_instance(ses) != OF_STATUS_OK) {
OF_PRINT_ERROR(("init_sender: ERROR: of_release_codec_instance() failed\n"))
goto error;
}
/*
* determine the practical maximum k and n parameters, taking into
* account the code/codec limitations and the desired code_rate.
* The idea is to have max_k maximum, given max_n and code_rate, for
* optimal erasure recovery performances.
*/
tmp_max_k = (UINT32)floor((double)max_n * code_rate);
max_k = min(tmp_max_k, max_k);
max_n = min((UINT32)((double)max_k / code_rate), max_n);
/* we can now compute the required blocking structure */
of_compute_blocking_struct(max_k, object_size, symbol_size, &bs);
tot_nb_blocks = bs.nb_blocks;
/*
* adjust tot_nb_encoding_symbols and tot_nb_encoding_symbols variables, now we know
* the exact blocking structure.
*/
tot_nb_encoding_symbols = (bs.I * (int)floor((double)(bs.A_large) / code_rate)) +
((bs.nb_blocks - bs.I) * (int)floor((double)(bs.A_small) / code_rate));
ASSERT(tot_nb_encoding_symbols <= tot_nb_source_symbols + tot_nb_repair_symbols);
tot_nb_repair_symbols = tot_nb_encoding_symbols - tot_nb_source_symbols;
OF_PRINT_LVL(1, ("Blocking_struct:\n\ttot_nb_source_symbols=%d, tot_nb_repair_symbols=%d, tot_nb_encoding_symbols=%d, code_rate=%.3f\n\tI=%d, tot_nb_blocks=%d, A_large=%d, A_small=%d\n",
tot_nb_source_symbols, tot_nb_repair_symbols, tot_nb_encoding_symbols, code_rate,
bs.I, tot_nb_blocks, bs.A_large, bs.A_small))
/*
* allocate and inix#tialize the original source and repair symbol buffers.
*/
if ((orig_symb = (char**)calloc(tot_nb_encoding_symbols, sizeof(char*))) == NULL) {
OF_PRINT_ERROR(("init_sender: ERROR: out of memory\n"))
goto no_mem;
}
/* source symbol buffers first... */
for (src_idx = 0; src_idx < tot_nb_source_symbols; src_idx++) {
char *symb;
UINT32 i;
/*
* buffer is 0'ed... Leave it like that, except for the first
* four bytes where we copy the pkt seq number.
*/
if ((symb = (char*)calloc(1, symbol_size)) == NULL) {
OF_PRINT_ERROR(("init_sender: ERROR: out of memory\n"))
goto no_mem;
}
orig_symb[src_idx] = symb;
/* fill each source symbol with some random content, except the first
* word which is equal to the symbol ID. This is useful to test the symbol
* integrity after decoding */
for (i = 0; i < symbol_size; i++) {
symb[i] = (char)rand();
}
*(UINT32 *)symb = (UINT32)src_idx;
//symb[src_idx%symbol_size]=1;
//of_print_composition(symb, symbol_size);
}
/* ... and then repair symbol buffers */
for (rep_idx = tot_nb_source_symbols; rep_idx < tot_nb_encoding_symbols; rep_idx++) {
orig_symb[rep_idx] = (char*)calloc(1, symbol_size);
if (orig_symb[rep_idx] == NULL) {
OF_PRINT_ERROR(("init_sender: ERROR: out of memory\n"))
goto no_mem;
}
/* repair symbols will be initialized later... */
}
/*
* now allocate the block and symbol control structures.
*/
if (!(blk_cb_tab = (block_cb_t*)calloc(tot_nb_blocks, sizeof(block_cb_t)))) {
OF_PRINT_ERROR(("init_sender: ERROR: out of memory\n"))
goto no_mem;
}
if (!(symb_cb_tab = (symbol_cb_t*)calloc(tot_nb_encoding_symbols, sizeof(symbol_cb_t)))) {
OF_PRINT_ERROR(("init_sender: ERROR: out of memory\n"))
goto no_mem;
}
/* ...and initialize the various block/symbol control structures */
src_idx = 0;
src_symb_cb = symb_cb_tab;
rep_idx = tot_nb_source_symbols;
rep_symb_cb = &(symb_cb_tab[tot_nb_source_symbols]);
max_n_4_any_blk = 0;
for (sbn = 0, blk = blk_cb_tab; sbn < tot_nb_blocks; sbn++, blk++) {
if (sbn < (UINT32)bs.I) {
k = bs.A_large;
} else {
k = bs.A_small;
}
n = (UINT32)floor((double)k / code_rate);
max_n_4_any_blk = (n < max_n_4_any_blk) ? max_n_4_any_blk : n;
/* init block control block */
blk->sbn = sbn;
blk->k = k;
blk->n = n;
blk->first_src_symbol_idx = src_idx;
blk->first_repair_symbol_idx = rep_idx;
blk->is_decoded = false;
blk->nb_symbols_received = 0;
OF_TRACE_LVL(1, ("init_sender: block: sbn=%d, k=%d, n=%d, first_src_symbol_idx=%d, 1st_rep_symbol_idx=%d\n",
sbn, blk->k, blk->n,
blk->first_src_symbol_idx, blk->first_repair_symbol_idx))
/* init source symbols control block */
for (esi = 0; esi < k; esi++, src_symb_cb++, src_idx++) {
src_symb_cb->esi = esi;
src_symb_cb->sbn = sbn;
}
/* and init repair symbols control block */
for (esi = k; esi < n; esi++, rep_symb_cb++, rep_idx++) {
rep_symb_cb->esi = esi;
rep_symb_cb->sbn = sbn;
}
}
/*
* allocate the table containing the various symbols of a block. This table
* is allocated once and reused by all blocks of the object, with pointers to
* different symbols of course, for encoding purposes.
*/
if (!(encoding_symbols_tab = (void**)calloc(max_n_4_any_blk, sizeof(void*)))) {
OF_PRINT_ERROR(("init_sender: ERROR: out of memory\n"))
goto no_mem;
}
#ifdef WIN32
QueryPerformanceCounter(&tv1);
OF_PRINT(("init_end=%I64f init_time=%I64f\n",
(double)tv1.QuadPart / (double)freq.QuadPart,
(double)(tv1.QuadPart-tv0.QuadPart) / (double)freq.QuadPart ))
#else
gettimeofday(&tv1, NULL);
timersub(&tv1, &tv0, &tv_delta);
OF_PRINT(("init_end=%ld.%ld init_time=%ld.%06ld\n",
tv1.tv_sec, tv1.tv_usec, tv_delta.tv_sec, tv_delta.tv_usec))
#endif
//INIT SENDER SOCKET
// >>> Step #1 <<<
// Create a socket
// - AF_INET is Address Family Internet and SOCK_DGRAM is datagram
client_s = socket(AF_INET, SOCK_DGRAM, 0);
if (client_s < 0)
{
printf("*** ERROR - socket() failed \n");
exit(-1);
}
printf("*** Sender -- socket created \n");
// >>> Step #2 <<<
// Fill-in server1 socket's address information
server_addr.sin_family = AF_INET; // Address family to use
server_addr.sin_port = htons(PORT_NUM); // Port num to use
server_addr.sin_addr.s_addr = inet_addr(IP_ADDR); // IP address to use
printf("***we have a client, and will sent message to server_addr ...server.. will receive messages.. sss\n");
return OF_STATUS_OK;
no_mem:
error:
return OF_STATUS_ERROR;
}
of_status_t
encode (void)
{
of_session_t *ses; /* pointer to a codec instance */
block_cb_t *blk; /* temporary pointer within the blk_cb_tab[] */
UINT32 sbn; /* block sequence number */
UINT32 k; /* k parameter for a given block. Warning, the last block might be shorter */
UINT32 n; /* n parameter for a given block. Warning, the last block might be shorter */
UINT32 esi; /* Encoding Symbol ID */
UINT32 i;
/*
* go through each block of the object, initialize all the structures
* and create repair symbols.
*/
#ifdef WIN32
QueryPerformanceCounter(&tv0);
OF_PRINT(("encoding_start=%lI64f\n", (double)tv0.QuadPart / (double)freq.QuadPart))
#else
gettimeofday(&tv0, NULL);
OF_PRINT(("encoding_start=%ld.%ld\n", tv0.tv_sec, tv0.tv_usec))
#endif
for (sbn = 0, blk = blk_cb_tab; sbn < tot_nb_blocks; sbn++, blk++) {
k = blk->k;
n = blk->n;
/* don't forget to initialize the encoding symbol tab, used by the
* FEC codec during encoding, since we cannot use the orig_symb table
* where the source/repair symbols of a block are not sequential :-( */
for (esi = 0; esi < k; esi++) {
encoding_symbols_tab[esi] = (void*)(orig_symb[blk->first_src_symbol_idx + esi]);
}
for (; esi < n; esi++) {
encoding_symbols_tab[esi] = (void*)(orig_symb[blk->first_repair_symbol_idx + (esi - k)]);
}
/*
* create the codec instance and initialize it accordingly.
* The case of a parity check matrix given in a file is handled
* differently...
*/
#ifdef OF_USE_LDPC_FROM_FILE_CODEC
if (codec_id == OF_CODEC_LDPC_FROM_FILE_ADVANCED)
{
if (of_create_codec_instance(&ses, codec_id, OF_ENCODER, of_verbosity) != OF_STATUS_OK) {
OF_PRINT_ERROR(("ERROR: of_create_codec_instance() failed for codec_id %d\n", codec_id))
goto error;
}
of_ldpc_ff_parameters_t params;
params.encoding_symbol_length = symbol_size;
params.pchk_file = ldpc_matrix_file_name;
if (of_set_fec_parameters(ses, (of_parameters_t*)¶ms) != OF_STATUS_OK) {
OF_PRINT_ERROR(("ERROR: of_set_fec_parameters() failed for codec_id %d\n", codec_id))
goto error;
}
k = params.nb_source_symbols;
n = params.nb_source_symbols + params.nb_repair_symbols;
} else
#endif
{
ses = create_and_init_codec_instance(codec_id, OF_ENCODER, k, n, blk);
if (ses == NULL) {
OF_PRINT_ERROR(("ERROR: create_and_init_codec_instance() failed for codec_id %d/OF_ENCODER\n", codec_id))
goto error;
}
}
/*
* perform encoding and finally release the FEC codec instance.
*/
for (esi = k; esi < n; esi++) {
if (of_build_repair_symbol(ses, encoding_symbols_tab, esi) != OF_STATUS_OK) {
OF_PRINT_ERROR(("ERROR: of_build_repair_symbol() failed\n"))
goto error;
}
}
//SEND THE PACKETS TO THE RECEIVE!!!
#ifdef WIN
WORD wVersionRequested = MAKEWORD(1,1); // Stuff for WSA functions
WSADATA wsaData; // Stuff for WSA functions
#endif
int server_s; // Server socket descriptor
struct sockaddr_in server_addr; // Server Internet address
struct sockaddr_in client_addr; // Client Internet address..i.e //receiver
struct in_addr client_ip_addr; // Client IP address
int addr_len; // Internet address length
char out_buf[symbol_size]; // Output buffer for data
char in_buf[symbol_size]; // Input buffer for data
int retcode; // Return code
#ifdef WIN
// This stuff initializes winsock
WSAStartup(wVersionRequested, &wsaData);
#endif
// >>> Step #3 <<<
// Now send the message to server. The "+ 1" is for the end-of-string
// delimiter
printf("*** Start sending messages.. \n");
//n is number of symbols to sent -- repair + original..
int j= 0;
for (j=0; j < n ; j++ )
{
//fprintf ("sending test..first char is %c and %c",(char*) ///encoding_symbols_tab[j]);
retcode = sendto(client_s, (const void*) encoding_symbols_tab[j], symbol_size, 0,
(struct sockaddr *)&server_addr, sizeof(server_addr) );
if (retcode < 0)
{
printf("*** ERROR - sendto() failed.. retcode is %d \n", retcode);
exit(-1);
}
else
printf("*** ERROR - sendto() successs \n");
}
Some code of the receiver:
// >>> Step #1 <<<
// Create a socket
// - AF_INET is Address Family Internet and SOCK_DGRAM is datagram
server_s = socket(AF_INET, SOCK_DGRAM, 0);
if (server_s < 0)
{
printf("*** ERROR - socket() failed \n");
exit(-1);
}
else
printf("*** Created server socket good. Server socket is %d \n", server_s);
// >>> Step #2 <<<
// Fill-in my socket's address information
server_addr.sin_family = AF_INET; // Address family to use
server_addr.sin_port = htons(PORT_NUM); // Port number to use
server_addr.sin_addr.s_addr = htonl(IP_ADDR); // Listen on any IP address
printf("***We have a server socket; and now we will try to bind it with the IP_ADDR-local host -- that we sent.. \n port nr %d & ip %s", PORT_NUM, IP_ADDR);
retcode = bind(server_s, (struct sockaddr *)&server_addr,
sizeof(server_addr));
if (retcode < 0)
{
printf("*** ERROR - bind() failed \n");
exit(-1);
}
else
printf("***Bind succeed.. \n");
//Storing all messages in in_buf -- here we will receive one; rest in code in decode-function.
// >>> Step #3 <<<
// Wait to receive a message from client
pthread_t thread1;
int iret1;
char *message1 = "Thread 1";
iret1 = pthread_create( &thread1, NULL, waitToReceiveMessageFromClient, (void*) message1);
#include <stdlib.h>
#include <errno.h>
#include <strings.h>
...
retcode = some_system_call(...);
if (retcode == -1)
{
int err = errno;
fprintf(stderr, "*** ERROR - bind() failed:%d(%s)\n"
, err, strerror(err)
);
exit(EXIT_FAILURE);
}
BTW: there is also perror()