passing struct variable name in write api () - c

There was problem in receiving and processing the packets because i used to send just a buffer not 'saddr' and its 'size'
Hence i used structure to declare all the members ow instead of the field buffer in write() api i need to send the struct variable name . do i need to use pointer there?
struct fields
{
unsigned char buffer[1024];
socklen_t saddr_size;
} data;

First of all recvfrom returns the length of the message.
n = recvfrom(sock,buffer,1024,0,(struct sockaddr *)&from, &length);
if (n < 0) error("recvfrom");
Here length is the size of the socket structure you are using. This must be initialized prior to the call to recvfrom so that the kernel knows how much space is available to return the socket address.
also, note that (struct sockaddr *)&from will have the address of the remote socket used to send the datagram.
Now, in your call
data_size = recvfrom(sock_raw , buffer , 1024, 0 , &saddr , (socklen_t*)&saddr_size);
int cont= write(logfile,&data,data_size);
data_size will have the length of the message. But, size of data structure is more than the size of data_size. so, write may not write complete data to the logfile.
and make a note of Klas Lindbäck's comment. That is what you needed.
Please see the answer here.

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
struct fields
{
unsigned char buffer[1024];
struct sockaddr saddr;
socklen_t saddr_size;
} data;
int main()
{
int saddr_size;
struct fields data; // Note: this variable will hide the global variabledata.
struct sockaddr saddr;
ssize_t data_size;
int sock_raw, logfile=1;
// Need to insert code to create raw socket.
data_size = recvfrom(sock_raw, data.buffer, 1024, 0, &data.saddr,
&data.saddr_size);
int cont = write(logfile, &data, sizeof data);
return 0;
}

Related

problem in create packet using struct in c

I wrote a c program that listen to 443 port and receives ssl packets :
#include <errno.h>
#include <ctype.h>
#include <limits.h>
#include <string.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/stat.h>
#include <stdio.h>
#define MAX_SIZE 10000
struct ssl_header {
uint8_t type;
uint16_t version;
uint16_t length;
};
struct handshake {
struct ssl_header hdr;
uint8_t type;
unsigned int length[3];
unsigned int ssl_version[2];
char random[32];
};
void *message_processing(int sockfd){
char *buff = calloc(MAX_SIZE + 1, sizeof (char));
struct handshake *pkt;
pkt = calloc (1, sizeof (struct handshake));
while (1) {
int len_of_read_data = read( sockfd, buff, MAX_SIZE);
if (len_of_read_data > 0) {
memcpy(pkt, buff, sizeof (struct handshake) );
FILE* file = fopen("logfile", "a");
fprintf (file, "*********************************\n");
fprintf (file, "type1 : %u\n", pkt->hdr.type );
fprintf(file, "version1 : %u\n", pkt->hdr.version);
fprintf(file, "len1 : %u\n", pkt->hdr.length);
fprintf(file, "type2 : %u\n", pkt->type);
fprintf(file, "len2 : %u%u%u\n", pkt->length[0],pkt->length[1], pkt->length[2] );
fprintf(file, "version2 : %u.%u\n", pkt->ssl_version[0], pkt->ssl_version[1]);
fprintf(file, "random : %s\n", pkt->random);
fclose(file);
}
}
}
int main () {
struct sockaddr_in serv_addr;
int sock_descriptor = socket(AF_INET, SOCK_STREAM, 0);
int trueval = 1;
setsockopt(sock_descriptor, SOL_SOCKET, SO_REUSEPORT | SO_REUSEADDR, (char *)&trueval, sizeof(trueval));
bzero((char *) &serv_addr, sizeof (serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(443);
bind(sock_descriptor, (struct sockaddr *) &serv_addr, sizeof (serv_addr));
listen(sock_descriptor, 50);
while (1) {
struct sockaddr_in cli_addr;
socklen_t clilen;
clilen = sizeof(cli_addr);
int client_socket = accept(sock_descriptor, (struct sockaddr *) &cli_addr, &clilen);
message_processing(client_socket);
pthread_t pid;
pthread_create(&pid, NULL, (void *) message_processing, &client_socket);
pthread_join(pid, NULL);
}
}
I create structures from this link : http://blog.fourthbit.com/2014/12/23/traffic-analysis-of-an-ssl-slash-tls-session/
when i run the program and connect to it using curl -I https://127.0.0.1:443 --insecure, it receives some data . the problem is when i print that data in logfile file , i get these value that all are incorrect except type1 :
*********************************
type1 : 22
version1 : 513
len1 : 256
type2 : 0
len2 : 31543142363974688046409855404
version2 : 4270624758.750651113
random : �&,�X�I�Y��|}
i'm new in c and specially in struct and i'm not sure the problem is occurred when i create the structs or when i try to print fields.
can anybody help to figure out the problem.
You have a problem with wrong data types and with padding of your structures.
From your link, the TLS header contains:
1 byte type
2 bytes version
2 bytes length
Your attempt to map this to a structure has some flaw:
struct ssl_header {
uint8_t type;
uint16_t version;
uint16_t length;
};
For most architectures, a uint8_t has no specific alignment requirements while uint16_t is probably aligned on a 2byte boundary.
This is achieved by inserting invisible padding bytes.
While the header is 5 bytes, your struct contains 6 bytes or even more.
You might try to address this by using packed structs.
The second problem is you are using wrong types in your arrays.
The protocol definition contains a length field of 3 bytes and a version field of 2 bytes. In total these are 5 bytes.
Your struct looks like this:
unsigned int length[3];
unsigned int ssl_version[2];
This means you have 5 integers meaning 10, 20 or even 40 bytes in total.
Additionally you will have padding bytes also in this structure.
The layout of your structures is far off of the protocol definition.
You should not try to read a buffer directly into a memory location that is interpreted as a struct.
Instead you should read and handle each field separately. Then you can properly handly endianess, integer fields of any length and don't need to take care about padding in your structs.

Program to establish connection then print out data it receives in C (sockets)

So I'm trying to get used to sockets, as I need to use them to create an intrusion detection program for upcoming coursework.
Something im trying to do at the moment is simply set up a socket file descriptor, bind it to an address, let it listen for any incoming requests, accept them then write them to a file.
The problems i'm having at the moment is, though what I think I'm doing here is correct, I kind of lost my way past the listen() call. I've tried to figure this out and look up the functions but something just isn't clicking at the moment. I've been at this for the past 6 hours and I've hit a dead end.
This code causes a segmentation fault, no doubt caused by the attempt at writing from the connection stream to the output stream.
Two main things I'd really appreciate:
A) Is my current understanding of whats happening (displayed by comments) correct?
B) If anyone could help me with the segmentation fault or suggest a better way to get the data receieved after establishing a connection out to a file that'd be great.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netdb.h>
#define MYPORT 3490
#define BACKLOG 10
int main(void)
{
int sockfd = (AF_INET, SOCK_STREAM, 0);
//creates socket file descriptor
struct sockaddr_in servaddr;
// creates sockaddr_in structure
memset(&servaddr, 0, sizeof(servaddr));
//zeros out values in servaddr
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(MYPORT);
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
//sets contraints for servaddr
bind(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr));
//binds sockfd socket file descriptor to a sockaddr pointer pointing to
//memory location of our sockaddr_in servaddr
listen(sockfd, BACKLOG);
//listen for incoming connections
struct sockaddr their_addr;
socklen_t addr_size;
int new_fd;
//initialise sockaddr to store connector/clients socket address
//create socklen_t (dont know what this is) for the size of their socket
//new_fd for a new socket
addr_size = sizeof(their_addr);
new_fd = accept(sockfd, (struct sockaddr*) &their_addr, &addr_size );
//set the new socket equal to the result of our accept()
//accept takes the first connection queued on the host socket, pointer
//to a sockaddr where the connecting socket will be returned and
//the size of the structure to be allocated
FILE * conn_f = fdopen(new_fd, "w+");
FILE * output_f = fopen("receiver.txt", "w+");
//Here I try and set up two streams.
//One connection stream - conn_f which takes input from our new socket
//One output stream output_f - which writes to a text file
char *line = NULL;
size_t len = 0;
ssize_t bytes;
while ((bytes = getline(&line, &len, conn_f)) != -1) {
printf("Retrieved line of length %zu : %s\n", bytes, line);
fwrite(line, sizeof(char), bytes, output_f);
}
free(line);
//This was my attempt at reading the input line by line from my connection
//stream, (conn_f) and writing it to my output stream (output_f)
//I think this is causing the seg fault ^^
close(conn_f);
close(output_f);
return 0;
}

UDP C Server sendto() error: Can't assign requested address

I'm writing a basic Client/Server program in C, using UDP. The idea of the program is that the client sends a message to the server, the server receives it, then echoes it back to the client (the goal being to measure RTT for UDP). Unfortunately, on the server side, when the program attempts to call sendto() to echo the message, I receive the error "Can't assign requested address".
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#include <fcntl.h>
#define SERVER_PORT 7000
#define MAX_PENDING 10
#define MAX_LINE 1024000
int main()
{
struct sockaddr_in sin, sout;
socklen_t soutLen;
char buf[MAX_LINE];
int len;
int msgLen;
int s;
char *msg;
if( (s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0){
perror("could not establish UDP socket");
exit(1);
}
/* build address data structure */
bzero((char *)& sin, sizeof( sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(SERVER_PORT);
if( (bind(s, (struct sockaddr *)&sin, sizeof(sin))) < 0){
perror("udpServer: bind");
exit( 1);
}
while(1){
if((msgLen = recvfrom(s, buf, sizeof(buf), 0,(struct sockaddr *)&sout, &soutLen))<0){
perror("udpServer: recvfrom()");
exit( 1);
}
if( (sendto(s, buf, msgLen, 0, (struct sockaddr *)&sout, sizeof(sout)))<0 ){
perror("udpServer: sendto()");
exit( 1);
}
free(msg);
}
}
Thanks in advance: I'm pretty new to C, so any advice is much appreciated!
The problem is that your sout you pass to sendto is not correct, because you are not correctly setting it's size when passing it to recvfrom:
man recvfrom:
ssize_t
recvfrom(int socket, void *restrict buffer, size_t length,
int flags, struct sockaddr *restrict address,
socklen_t *restrict address_len);
If address is not a null pointer and the socket is not connection-oriented, the source address of the message is filled in. The address_len argument is a
value-result argument, initialized to the size of the buffer associated with address, and modified on return to indicate the actual size of the address
stored there.
When you pass &sout to recvfrom, you also have to tell recvfrom the size of the structure you're passing in so it knows how much data it can write there -- soutLen is both an in parameter and an out parameter. Since you are not initializing soutLen, it probably has some value smaller than the actual size of the structure, which means that what you end up with in sout is not valid.
So you need to initialize soutLen:
struct sockaddr_in sin, sout;
socklen_t soutLen = sizeof(sout);
You should then pass this value as the size to sendto instead of sizeouf(sout) (this may not be required but it's good practice):
if( (sendto(s, buf, msgLen, 0, (struct sockaddr *)&sout, soutLen))<0 ){
Also just as a note, you are freeing msg which you never allocated. This is unrelated but might cause problems later.
Hope this helps.

c- valgrind (Invalid free() / delete / delete[] / realloc()) Socketing

I am writing a simple program using sockets to receive actual date from server.
I am getting this error and i don't know where i am making a mistake.
Client:
/* Make the necessary includes and set up the variables. */
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
int main ()
{
int sockfd;
socklen_t len;
struct sockaddr_in address;
int result;
int id=2, answer, length;
char *s;
/* Create a socket for the client. */
sockfd = socket (AF_INET, SOCK_STREAM, 0);
/* Name the socket, as agreed with the server. */
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr ("127.0.0.1");
address.sin_port = htons (9734);
len = sizeof (address);
/* Now connect our socket to the server's socket. */
result = connect (sockfd, (struct sockaddr *) &address, len);
if (result == -1)
{
perror ("oops: netclient");
exit (1);
}
/* We can now read/write via sockfd. */
write(sockfd, &id, sizeof(id)); /* sending the request id */
read(sockfd, &answer, sizeof(answer)); /* receiving the answer id*/
if(answer==1002){
printf("Odebrano wlasciwa odpowiedz\n");
read(sockfd, &length, sizeof(length)); /* receiving the answer string length*/
s=(char*)malloc(length*sizeof(char)); /* receiving the string with the date */
read(sockfd, s, length);
printf ("Date from server = %s\n", s);
}
free(s);
close (sockfd);
exit (0);
}
Server:
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <signal.h>
#include <unistd.h>
#include <time.h>
#include <string.h>
int main ()
{
int server_sockfd, client_sockfd;
int length;
char *s;
int id;
int answer=1002;
socklen_t server_len, client_len;
time_t rtime;
struct tm *timeinfo;
struct sockaddr_in server_address;
struct sockaddr_in client_address;
server_sockfd = socket (AF_INET, SOCK_STREAM, 0);
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = htonl (INADDR_ANY);
server_address.sin_port = htons (9734);
server_len = sizeof (server_address);
bind (server_sockfd, (struct sockaddr *) &server_address, server_len);
/* Create a connection queue and wait for clients. */
listen (server_sockfd, 5);
while (1)
{
printf ("server waiting\n");
/* Accept connection. */
client_len = sizeof (client_address);
client_sockfd = accept (server_sockfd,
(struct sockaddr *) &client_address,
&client_len);
/* We can now read/write to the client on client_sockfd.
The five second delay is just for this demonstration. */
read(client_sockfd, &id, sizeof(int)); /*receive request id */
if(id==2){
write(client_sockfd, &answer, sizeof(int)); /* sending an answer_id*/
time(&rtime);
timeinfo=localtime(&rtime);
s=(char*)malloc(sizeof(asctime(timeinfo))*sizeof(char));
printf("%s\n", asctime(timeinfo));
s=asctime(timeinfo);
printf("Size of s:%lx\n", sizeof(s));
length = htons(strlen(s));
write (client_sockfd, &length, sizeof(length)); /* sending the answer string length to the client */
printf("Date: %s\n", s);
write (client_sockfd, s, length); /* sending string with date to the server */
}
free(s);
close (client_sockfd);
}
}
I am almost certain that there is something wrong with allocing/freeing the space with the string containing actual date but i can't see the actual mistake.
EDIT:
Actually, i didn't know how to solve this problem in this mentioned way but i've came up with other idea.
I just send the result of asctime(timeinfo) over the server without using char* s.
So i don't write the date to char *s.
Program works fine now with no errors but i guess there is a way to do it some other way.
Well, even though, many thanks for the help, was helpful.
In your server, you overwrite s with asctime(...) after allocating it. This leaks the original memory. Also, the return value of asctime is a static buffer that cannot be freed.
Here's an excerpt from your code:
char *s;
if(answer==1002){
printf("Odebrano wlasciwa odpowiedz\n");
read(sockfd, &length, sizeof(length)); /* receiving the answer string length*/
s=(char*)malloc(length*sizeof(char)); /* receiving the string with the date */
printf ("Date from server = %s\n", s);
}
free(s);
Note what happens if 'answer' is not equal to 1002 -- you're calling free() on an uninitialized value. That is likely the cause of the error you are seeing. (This same mistake is present in both programs)
Refering the server code:
Here you allocate memory to s:
s=(char*)malloc(sizeof(asctime(timeinfo))*sizeof(char));
Here you overwrite the pointer with the value receive from asctime() so the original value returned by malloc() is lost introducing a memory leak:
s=asctime(timeinfo);
Here you then try to free what had been received from asctime(), which is a reference to static memory and gherefore cannot be freed.
free(s);

getsockname() c not setting value

I'm trying to get the local IP used for a connection established. However, for some reason, I'm unable to use getsockname because it never sets any data in my sockaddr.
int fd = socket(/* params */);
int len;
struct sockaddr_in _self;
/* Connection code, I know the connection succeeds and I've tested */
memset(&_self, 0, sizeof (struct sockaddr_in));
getsockname(fd, (struct sockaddr *) &_self, &len);
printf("%s\n", inet_ntoa(_self.sin_addr);
However, when the program gets to printf, it always terminates due to a 'Segmentation fault', which I think is when it tries to access memory that it hasn't set (am I correct in this assumption?) If so, does that mean that getsockname is failing?
You have to initialise len to be the maximum allowed size before calling getsockname() (ie, the size of the structure). This length value is them modified by the call to contain the actual length.
You should also ensure that the socket descriptor has been bound. Your test seems to indicate it's for an established session but the code is unclear in that it only contains a socket() call.
As a baseline, use the following program:
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
int main (void) {
int fd = socket (AF_INET, SOCK_STREAM, 0);
struct sockaddr_in _self;
int len = sizeof (_self);
memset (&_self, 0, len);
bind(fd, (struct sockaddr *) &_self, len);
memset (&_self, 42, len);
getsockname (fd, (struct sockaddr *) &_self, &len);
printf ("%s\n", inet_ntoa (_self.sin_addr));
return 0;
}
This outputs 0.0.0.0 as expected.

Resources