I'm writing a sample of c udp socket.
This is the client
#include <stdlib.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <arpa/inet.h>
int
main(int argc, char *argv[]) {
if (argc < 3) {
fprintf(stderr, "Usage: %s ip port\n", argv[0]);
exit(1);
}
int sock;
char *server_ip;
unsigned short server_port;
struct sockaddr_in cliAddr, serAddr;
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
fprintf(stderr, "socket failed\n");
exit(1);
}
server_ip = argv[1];
server_port = atoi(argv[2]);
memset(&cliAddr, 0, sizeof(cliAddr));
cliAddr.sin_family = AF_INET;
cliAddr.sin_addr.s_addr = htonl(INADDR_ANY);
cliAddr.sin_port = htons(21152);
if (bind(sock, (struct sockaddr *) &cliAddr, sizeof(struct sockaddr)) < 0) {
fprintf(stderr, "bind failed\n");
exit(1);
}
memset(&serAddr, 0, sizeof(serAddr));
serAddr.sin_family = AF_INET;
serAddr.sin_addr.s_addr = inet_addr(server_ip);
serAddr.sin_port = htons(server_port);
if (sendto(sock, "hello", 5, 0, (struct sockaddr *) (&serAddr), sizeof(serAddr)) == -1) {
fprintf(stderr, "sendto failed\n");
exit(1);
}
printf("send success\n");
int n;
char recvstr[50];
if ((n = recvfrom(sock, &recvstr, 50, 0, NULL, NULL)) < 0) {
fprintf(stderr, "recvfrom failed\n");
exit(1);
}
printf("receive success: %s\n", recvstr);
printf("from %s:%d\n", inet_ntoa(serAddr.sin_addr), ntohs(serAddr.sin_port));
exit(0);
}
And this is the server
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <string.h>
#include <arpa/inet.h>
int
main(int argc, char *argv[]) {
if (argc < 2) {
fprintf(stderr, "Usage: %s port\n", argv[0]);
exit(1);
}
int sock, n;
struct sockaddr_in servaddr, cliaddr;
char recvstr[50];
socklen_t cliaddrlen;
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
fprintf(stderr, "socket failed\n");
exit(1);
}
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(atoi(argv[1]));
if (bind(sock, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
fprintf(stderr, "bind failed\n");
exit(1);
}
cliaddrlen = sizeof(cliaddr);
if ((n = recvfrom(sock, recvstr, 50, 0, (struct sockaddr *) &cliaddr, &cliaddrlen)) < 0) {
fprintf(stderr, "recvfrom failed\n");
exit(1);
}
printf("client ip: %s, client port: %d\n", inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port));
if (sendto(sock, "hello from server", 17, 0, (struct sockaddr *) &cliaddr, cliaddrlen) == -1) {
fprintf(stderr, "sendto failed\n");
exit(1);
}
printf("send success\n");
exit(0);
}
It works fine when client and server are in the local.
Such as "./server 21151" and "./client 127.0.0.1 21151".
The server will get:
client ip: 127.0.0.1, client port: 21152
send success
And the client will get:
send success
receive success: hello from serverB
from 127.0.0.1:21151
But when i change the ip to public ip.The client cannot get the response
from server.
The client will stop at the function recvfrom.
Any ideas?
Let me guess - you are running this on a Mac and the firewall is on? The default filtering rules will allow sending UDP out and receiving a response (the client), but will not allow to receive unsolicited datagrams on an open socket (the server).
Your code is fine otherwise, though you don't necessarily need to bind(2) the client side of the socket. The kernel will assign next available high-numbered port for the source. You might instead consider using connect(2) on the client if you plan on any extended conversation between given client and server.
You also always want to explicitly zero-terminate strings received from the network. Not doing this has been the source of endless remote exploits.
Related
I am using a for loop on the server-side to send data to all clients received from a single client. But it is unable to send to all clients. Instead, it just sends data to the only client who has sent the data. And also it is not printing the here printf line on the server console.
for(int j=0;j<i;j++){
printf("here");
send(fds[j], buffer, strlen(buffer), 0);
}
My server-side code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PORT 9999
int main(int argc, char* argv[]){
int sockfd, ret;
struct sockaddr_in serverAddr;
int newSocket;
struct sockaddr_in newAddr;
char lastchar = 'a';
socklen_t addr_size;
char buffer[1024];
pid_t childpid;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0){
printf("[-]Error in connection.\n");
exit(1);
}
printf("[+]Server Socket is created.\n");
memset(&serverAddr, '\0', sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(PORT);
serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
ret = bind(sockfd, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
if(ret < 0){
printf("[-]Error in binding.\n");
exit(1);
}
printf("[+]Bind to port %d\n", 4444);
if(listen(sockfd, 10) == 0){
printf("[+]Listening....\n");
}else{
printf("[-]Error in binding.\n");
}
int fds[10];
int i = 0;
while(1){
newSocket = accept(sockfd, (struct sockaddr*)&newAddr, &addr_size);
fds[i++] = newSocket;
if(newSocket < 0){
exit(1);
}
printf("Connection accepted from %s:%d\n", inet_ntoa(newAddr.sin_addr), ntohs(newAddr.sin_port));
if((childpid = fork()) == 0){
close(sockfd);
while(1){
recv(newSocket, buffer, 1024, 0);
if(strcmp(buffer, ":exit") == 0){
printf("Disconnected from %s:%d\n", inet_ntoa(newAddr.sin_addr), ntohs(newAddr.sin_port));
break;
}else{
if(buffer[0]==lastchar){
lastchar = buffer[strlen(buffer)-1];
bzero(buffer, sizeof(buffer));
strcpy(buffer, "Correct!");
}else{
bzero(buffer, sizeof(buffer));
strcpy(buffer, "Wrong!");
}
for(int j=0;j<i;j++){
printf("here");
send(fds[j], buffer, strlen(buffer), 0);
}
bzero(buffer, sizeof(buffer));
}
}
}
}
close(newSocket);
return 0;
}
My Client-side code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PORT 9999
int main(){
int clientSocket, ret;
struct sockaddr_in serverAddr;
char buffer[1024];
clientSocket = socket(AF_INET, SOCK_STREAM, 0);
if(clientSocket < 0){
printf("[-]Error in connection.\n");
exit(1);
}
printf("[+]Client Socket is created.\n");
memset(&serverAddr, '\0', sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(PORT);
serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
ret = connect(clientSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr));
if(ret < 0){
printf("[-]Error in connection.\n");
exit(1);
}
printf("[+]Connected to Server.\n");
while(1){
printf("Client: \t");
scanf("%s", &buffer[0]);
send(clientSocket, buffer, strlen(buffer), 0);
if(strcmp(buffer, ":exit") == 0){
close(clientSocket);
printf("[-]Disconnected from server.\n");
exit(1);
}
if(recv(clientSocket, buffer, 1024, 0) < 0){
printf("[-]Error in receiving data.\n");
}else{
printf("Server: \t%s\n", buffer);
}
}
return 0;
}
If I change my server code to the following can anybody tell me how to reply to all clients?
//Example code: A simple server side code, which echos back the received message.
//Handle multiple socket connections with select and fd_set on Linux
#include <stdio.h>
#include <string.h> //strlen
#include <stdlib.h>
#include <errno.h>
#include <unistd.h> //close
#include <arpa/inet.h> //close
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h> //FD_SET, FD_ISSET, FD_ZERO macros
#define TRUE 1
#define FALSE 0
#define PORT 8888
int main(int argc , char *argv[])
{
int opt = TRUE;
int master_socket , addrlen , new_socket , client_socket[30] ,
max_clients = 30 , activity, i , valread , sd;
int max_sd;
struct sockaddr_in address;
char buffer[1025]; //data buffer of 1K
//set of socket descriptors
fd_set readfds;
//a message
char *message = "ECHO Daemon v1.0 \r\n";
//initialise all client_socket[] to 0 so not checked
for (i = 0; i < max_clients; i++)
{
client_socket[i] = 0;
}
//create a master socket
if( (master_socket = socket(AF_INET , SOCK_STREAM , 0)) == 0)
{
perror("socket failed");
exit(EXIT_FAILURE);
}
//set master socket to allow multiple connections ,
//this is just a good habit, it will work without this
if( setsockopt(master_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&opt,
sizeof(opt)) < 0 )
{
perror("setsockopt");
exit(EXIT_FAILURE);
}
//type of socket created
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons( PORT );
//bind the socket to localhost port 8888
if (bind(master_socket, (struct sockaddr *)&address, sizeof(address))<0)
{
perror("bind failed");
exit(EXIT_FAILURE);
}
printf("Listener on port %d \n", PORT);
//try to specify maximum of 3 pending connections for the master socket
if (listen(master_socket, 3) < 0)
{
perror("listen");
exit(EXIT_FAILURE);
}
//accept the incoming connection
addrlen = sizeof(address);
puts("Waiting for connections ...");
while(TRUE)
{
//clear the socket set
FD_ZERO(&readfds);
//add master socket to set
FD_SET(master_socket, &readfds);
max_sd = master_socket;
//add child sockets to set
for ( i = 0 ; i < max_clients ; i++)
{
//socket descriptor
sd = client_socket[i];
//if valid socket descriptor then add to read list
if(sd > 0)
FD_SET( sd , &readfds);
//highest file descriptor number, need it for the select function
if(sd > max_sd)
max_sd = sd;
}
//wait for an activity on one of the sockets , timeout is NULL ,
//so wait indefinitely
activity = select( max_sd + 1 , &readfds , NULL , NULL , NULL);
if ((activity < 0) && (errno!=EINTR))
{
printf("select error");
}
//If something happened on the master socket ,
//then its an incoming connection
if (FD_ISSET(master_socket, &readfds))
{
if ((new_socket = accept(master_socket,
(struct sockaddr *)&address, (socklen_t*)&addrlen))<0)
{
perror("accept");
exit(EXIT_FAILURE);
}
//inform user of socket number - used in send and receive commands
printf("New connection , socket fd is %d , ip is : %s , port : %d
\n" , new_socket , inet_ntoa(address.sin_addr) , ntohs
(address.sin_port));
//send new connection greeting message
if( send(new_socket, message, strlen(message), 0) != strlen(message) )
{
perror("send");
}
puts("Welcome message sent successfully");
//add new socket to array of sockets
for (i = 0; i < max_clients; i++)
{
//if position is empty
if( client_socket[i] == 0 )
{
client_socket[i] = new_socket;
printf("Adding to list of sockets as %d\n" , i);
break;
}
}
}
//else its some IO operation on some other socket
for (i = 0; i < max_clients; i++)
{
sd = client_socket[i];
if (FD_ISSET( sd , &readfds))
{
//Check if it was for closing , and also read the
//incoming message
if ((valread = read( sd , buffer, 1024)) == 0)
{
//Somebody disconnected , get his details and print
getpeername(sd , (struct sockaddr*)&address , \
(socklen_t*)&addrlen);
printf("Host disconnected , ip %s , port %d \n" ,
inet_ntoa(address.sin_addr) , ntohs(address.sin_port));
//Close the socket and mark as 0 in list for reuse
close( sd );
client_socket[i] = 0;
}
//Echo back the message that came in
else
{
//set the string terminating NULL byte on the end
//of the data read
buffer[valread] = '\0';
send(sd , buffer , strlen(buffer) , 0 );
}
}
}
}
return 0;
}
When you call fork(), the child process effectively receives its own separate copy of the parent process's address-space. Since the child process's address-space is separate and independent from that of its parent process, any subsequent changes to variables in the parent process's address space will not be seen by the child process.
Since your server is calling fork() for each new TCP connection that is received, that means that each new TCP connection is getting its own address-space that includes it and any already-accepted sockets, but will never include any sockets that are accepted on the server after that client's process was spawned. That is likely why you aren't seeing all the file descriptors you expect in your fds array, when you iterate over it calling send().
My advice is to simply get rid of the fork() call. If you want to keep (and iterate over) a list of all connected clients' file-descriptors, then its much simpler to use a single-process model rather than a process-per-client model. If you need to react to incoming input data from any of the clients, you can use non-blocking I/O and block instead inside select() or poll() until one of the file descriptors in your list has incoming data ready for you to read.
The client program:
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define LEN 256
int main(int argc, char *argv[]) {
struct addrinfo hints;
struct addrinfo *result, *rp;
int sock, s, n, r;
char message[256] , receive[1024];
int msglen, recvlen;
if (argc < 3)
{
fprintf(stderr, "Usage: %s host port msg...\n", argv[0]);
exit(EXIT_FAILURE);
}
/* Obtain address(es) matching host/port */
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET; /* Allow IPv4 or IPv6 */
hints.ai_socktype = SOCK_STREAM; /* streaming socket */
hints.ai_flags = 0;
hints.ai_protocol = 0; /* Any protocol */
s = getaddrinfo(argv[1], argv[2], &hints, &result);
if (s != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
exit(EXIT_FAILURE);
}
/* getaddrinfo() returns a list of address structures.
Try each address until we successfully connect(2).
If socket(2) (or connect(2)) fails, we (close the socket
and) try the next address. */
for (rp = result; rp != NULL; rp = rp->ai_next) {
sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (sock == -1)
continue;
if (connect(sock, rp->ai_addr, rp->ai_addrlen) != -1)
break; /* Success */
close(sock);
}
if (rp == NULL) { /* No address succeeded */
fprintf(stderr, "Could not connect\n");
exit(EXIT_FAILURE);
}
/* Send remaining command-line arguments as separate
datagrams, and read responses from server */
while(1)
{
bzero(message, LEN );
fgets(message, LEN, stdin);
printf("The server sent: %s\n",message);
n = send(sock, message, strlen(message), 0);
{
fprintf(stderr, "Could not send\n");
exit(EXIT_FAILURE);
}
bzero(message, 255);
n = recv(sock, message, LEN, 0);
if (n < 0)
{
fprintf(stderr, "Could not receive\n");
exit(EXIT_FAILURE);
}
printf("The client received: %s\n", message);
int i = strncmp("Exit", receive, 4);
if(i == 0)
break;
}
return 0;
}
The server program:
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#define LEN 256
int main(int argc, char *argv[]) {
struct addrinfo hints;
struct addrinfo *result, *rp;
struct sockaddr_in storage;
int sock, s,l,a,n;
char receive[LEN], response[1024];
int recvlen = strlen(receive);
pid_t childpid;
if (argc != 2)
{
fprintf(stderr, "Usage: %s port\n", argv[0]);
exit(EXIT_FAILURE);
}
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET; /* Allow IPv4 or IPv6 */
hints.ai_socktype = SOCK_STREAM; /* Datagram socket */
hints.ai_flags = 0; /* For wildcard IP address */
hints.ai_protocol = 0; /* Any protocol */
hints.ai_canonname = NULL;
hints.ai_addr = NULL;
hints.ai_next = NULL;
s = getaddrinfo(NULL, argv[1], &hints, &result);
if (s != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
exit(EXIT_FAILURE);
}
/* getaddrinfo() returns a list of address structures.
Try each address until we successfully bind(2).
If socket(2) (or bind(2)) fails, we (close the socket
and) try the next address. */
for (rp = result; rp != NULL; rp = rp->ai_next) {
sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (sock == -1)
continue;
if (bind(sock, rp->ai_addr, rp->ai_addrlen) == 0)
break; /* Success */
close(sock);
}
if (rp == NULL) { /* No address succeeded */
fprintf(stderr, "Could not bind\n");
exit(EXIT_FAILURE);
}
l = listen(sock, 5);
if(l != 0)
{
fprintf(stderr, "error in listening\n");
exit(EXIT_FAILURE);
}
socklen_t str_storage = sizeof(storage);
a = accept(sock, (struct sockaddr*)&storage, &str_storage);
if(a < 0)
{
fprintf(stderr, "the acceptance is not done\n");
exit(EXIT_FAILURE);
}
while(1)
{
bzero(receive, LEN);
n = recv(a, receive, LEN , 0);
if(n < 0)
{
fprintf(stderr, "error in reading\n");
exit(EXIT_FAILURE);
}
printf("The client message: %s\n ", receive);
bzero(receive, LEN);
fgets(receive, LEN, stdin);
n = send(a, receive, recvlen, 0);
if(n < 0)
{
fprintf(stderr, "error in replying\n");
exit(EXIT_FAILURE);
}
int i = strncmp("Exit", receive, 4);
if(i == 0)
break;
printf("The server message: %s\n", receive);
}
close(a);
return 0;
}
linux output both sides:
$ ./client localhost 5690
deeeksha hey
The server sent: deeeksha hey
Could not send
server output:
$ ./server 5690
The client message: deeeksha hey
n = send(sock, message, strlen(message), 0);
{
fprintf(stderr, "Could not send\n");
exit(EXIT_FAILURE);
}
Your client is executing this block no matter if the send was successful or not. It looks like you've forgot to check for if (n<0) but instead just had a block without any condition. Likely a case of copy & paste from somewhere else in your code by forgetting to copy the first line.
I am trying to implement TCP client, server program in C on Linux system. Here are my codes.
Client Source Code :
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main(int argc, char *argv[])
{
char *address;
// Create socket
int client_socket;
client_socket = socket(AF_INET, SOCK_STREAM, 0);
// Set - Up Server Address
struct sockaddr_in server_address;
server_address.sin_family = AF_INET;
server_address.sin_port = htons(8001);
inet_aton(address, &server_address.sin_addr.s_addr);
// Connect to the server
int connect_stat;
connect_stat = connect(client_socket, (struct sockaddr *) &server_address, sizeof(server_address));
if(connect_stat == -1)
printf("Not Connected\n");
else
printf(" Connected \n");
// Recieve from server
char response[256];
recv(client_socket, &server_address, sizeof(server_address), 0);
// Printing the Response data
printf("Data Recieved : %s\n",response);
// Destroy the socket
close(client_socket);
return 0;
}
Server Source Code :
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main(int argc, char *argv[])
{
// Address
char *address;
address = argv[1];
// Create message to send
char message[256] = "Connection Established";
// Create server socket
int server_socket;
server_socket = socket(AF_INET, SOCK_STREAM, 0);
// Set - Up Server Address
struct sockaddr_in server_address;
server_address.sin_family = AF_INET;
server_address.sin_port = htons(8001);
inet_aton(address, &server_address.sin_addr.s_addr);
// Bind it to an IP and PORT
bind(server_socket, (struct sockaddr *) &server_address, sizeof(server_address));
// Start listenting on address
listen(server_socket, 5);
// Start accepting the clients;
int client_socket;
client_socket = accept(server_socket, NULL, NULL);
// Send some data back to client
send(client_socket, message, sizeof(message), 0);
// Close the socket
close(server_socket);
close(client_socket);
return 0;
}
On passing an IP like 192.168.1.xxx to both client and server, server starts waiting for the clients but client always show not connected and thus no data received.
Client output :
root#kali:/home/mayank/Desktop/tcp_chat# ./tcp_client 192.168.1.111
Not Connected
Data Recieved :
But if i use INADDR_ANY instead of specific IP, it works. I know INADDR_ANY basically means it binds to all IP address, but why it is not binding to specific IP address which i want. Any suggestions, where i am wrong.
Instead of inet_aton(), you can also use
server_address.sin_addr.s_addr = inet_addr("IP address");
And use perror() after every function, like
client_socket = socket(...);
if (client_socket == -1)
perror("socket");
You are not doing any error checking, except on the connect() call. For example, you are getting an ENOTSOCK error because you are not checking whether socket() succeeds or fails.
Beyond that, on the client side, this statement:
inet_aton(address, &server_address.sin_addr.s_addr);
Should be this instead:
inet_aton(address, &server_address.sin_addr);
inet_aton() expects a pointer to a struct in_addr, but you are passing it a pointer to a uint32_t instead. In fact, the original code should not have even compiled because of that.
But, more importantly, your address variable is uninitialized, so you are passing a bad memory pointer to inet_aton(), and not checking its return value for failure.
Even if you could connect to the server, you are also passing the wrong output buffer to recv(), so you would end up writing garbage to the console.
Try this instead:
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main(int argc, char *argv[])
{
if (argc != 2)
{
printf("usage: %s <IPv4 address>\n", argv[0]);
return 0;
}
// Set - Up Server Address
struct sockaddr_in server_address = {0};
server_address.sin_family = AF_INET;
server_address.sin_port = htons(8001);
if (inet_aton(argv[1], &server_address.sin_addr) != 0)
{
printf("invalid IPv4 address specified\n");
return 0;
}
// Create socket
int client_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (client_socket == -1)
{
perror("socket() failed");
return 0;
}
// Connect to the server
if (connect(client_socket, (struct sockaddr *) &server_address, sizeof(server_address)) == -1)
{
perror("Not Connected");
}
else
{
printf("Connected\n");
// Receive from server
char response[256];
int numRecvd = recv(client_socket, response, sizeof(response), 0);
// Printing the Response data
if (numRecvd == -1)
perror("recv() failed");
else if (numRecvd == 0)
printf("Disconnected by server\n");
else
printf("Data Received: [%d] %.*s\n", numRecvd, numRecvd, response);
}
// Destroy the socket
close(client_socket);
return 0;
}
#include <netinet/in.h>
#include <arpa/inet.h>
int main(int argc, char *argv[])
{
// Set - Up Server Address
struct sockaddr_in server_address = {0};
server_address.sin_family = AF_INET;
server_address.sin_port = htons(8001);
if (argc >= 2)
{
if (inet_aton(argv[1], &server_address.sin_addr) != 0)
{
printf("invalid IPv4 address specified\n");
return 0;
}
}
else
server_address.sin_addr.s_addr = INADDR_ANY;
// Create message to send
char message[256] = "Connection Established";
// Create server socket
int server_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (server_socket == -1)
{
perror("socket() failed");
return 0;
}
// Bind it to an IP and PORT
if (bind(server_socket, (struct sockaddr *) &server_address, sizeof(server_address)) == -1)
{
perror("bind() failed");
}
// Start listenting on address
else if (listen(server_socket, 5) == -1)
{
perror("listen() failed");
}
// Start accepting the clients
else
{
int client_socket = accept(server_socket, NULL, 0);
if (client_socket == -1)
{
perror("accept() failed");
}
else
{
// Send some data back to client
int numSent = send(client_socket, message, sizeof(message), 0);
if (numSent == -1)
perror("send() failed");
else
printf("Data Sent: [%d] %.*s\n", numSent, numSent, message);
// Close the socket
close(client_socket);
}
}
// Destroy the socket
close(server_socket);
return 0;
}
I've written a pair of TCP client/server which each call getpeerucred on the other and then call ucred_getprojid print out the project id their respective peer. I see the following results:
Within within any distinct zone (global or zlogin to any single zone) the client/server pair both report proper project id from their peer.
# /usr/bin/id -p
uid=0(root) gid=0(root) projid=1(user.root)
# ./bind 5000
Binding to port: 5000
project id: 10
---------------
$ /usr/bin/id -p
uid=100(rpaisley) gid=10(staff) projid=10(group.staff)
$ ./connect 127.0.0.1 5000
project id: 1
With Trusted Extensions enabled using two differently labeled zones (it doesn't seem to matter if there's any dominance relationship, the same behavior applies) across a Multi-Level port both report 0 which is neither correct, nor the -1 claimed from the ucred_getprojid manual page for when the project ID is not available.
# /usr/bin/id -p
uid=0(root) gid=0(root) projid=1(user.root)
# ./bin/bind 2000
Binding to port: 2000
project id: 0
---------------
$ /usr/bin/id -p
uid=100(rpaisley) gid=10(staff) projid=10(group.staff)
$ ./bin/connect 10.10.10.1 2000
project id: 0
Source code for server (named bind) is below. Program requires -ltsol -lsocket -lnsl
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <ucred.h>
#include <unistd.h>
int
main(int argc, char **argv)
{
if(2 != argc) {
fprintf(stderr, "Usage: %s <port>\n", *argv);
return EXIT_FAILURE;
}
int port;
char unused;
if(1 != sscanf(argv[1], "%d%c", &port, &unused)) {
fprintf(stderr, "Failed to parse port: %s\n", argv[1]);
return EXIT_FAILURE;
}
int s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if(-1 == s) {
perror("socket");
return EXIT_FAILURE;
}
struct sockaddr_in local;
memset(&local, 0, sizeof(local));
local.sin_family = AF_INET;
local.sin_addr.s_addr = htonl(INADDR_ANY);
local.sin_port = htons(port);
printf("Binding to port: %d\n", port);
if(-1 == bind(s, (struct sockaddr *)&local, sizeof(local))) {
perror("bind");
close(s);
return EXIT_FAILURE;
}
if(-1 == listen(s, 1)) {
perror("listen");
close(s);
return EXIT_FAILURE;
}
int c;
struct sockaddr_in client;
unsigned int clientlen = sizeof(client);
c = accept(s, (struct sockaddr *)&client, &clientlen);
if(-1 == c) {
perror("accept");
close(s);
return EXIT_FAILURE;
}
close(s);
ucred_t *cred = NULL;
if(-1 == getpeerucred(c, &cred)) {
perror("getpeerucred");
close(c);
return EXIT_FAILURE;
}
printf("project id: %d\n", ucred_getprojid(cred));
ucred_free(cred);
close(c);
return EXIT_SUCCESS;
}
Source code for client (named connect) Program requires -ltsol -lsocket -lnsl
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <ucred.h>
#include <unistd.h>
int
main(int argc, char **argv)
{
if(3 != argc) {
fprintf(stderr, "Usage: %s <ip addr> <port>\n", *argv);
return EXIT_FAILURE;
}
int port;
char unused;
if(1 != sscanf(argv[2], "%d%c", &port, &unused)) {
fprintf(stderr, "Failed to parse port: %s\n", argv[2]);
return EXIT_FAILURE;
}
struct sockaddr_in srvaddr;
memset(&srvaddr, 0, sizeof(srvaddr));
srvaddr.sin_family = AF_INET;
srvaddr.sin_port = htons(port);
if(0 == inet_aton(argv[1], &srvaddr.sin_addr)) {
fprintf(stderr, "Address invalid: %s\n", argv[1]);
return EXIT_FAILURE;
}
int s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if(-1 == s) {
perror("socket");
return EXIT_FAILURE;
}
if(-1 == connect(s, (struct sockaddr *)&srvaddr, sizeof(srvaddr))) {
perror("connect");
close(s);
return EXIT_FAILURE;
}
ucred_t *cred = NULL;
if(-1 == getpeerucred(s, &cred)) {
perror("getpeerucred");
close(s);
return EXIT_FAILURE;
}
printf("project id: %d\n", ucred_getprojid(cred));
ucred_free(cred);
close(s);
return EXIT_SUCCESS;
}
I tried to setup a XSTUNT server on Linux(http://www.cis.nctu.edu.tw/~gis87577/xDreaming/XSTUNT/index.html) to do p2p traversal, but failed. I read the source code of it. I found the application creates two TCP sockets and then bind them to the two public IP addresses respectively. The remote client is able to connect only one of the public IP address.
So I wrote a simple server application to test this environment.
On the remote client, I use this two commands
"nc [public IP_A] [PORT]" and
"nc [public IP_B] [PORT]"
to try to connect to the server. Only one is successful, while the other fail. I have sniffer the traffic on the client, the nc which is failed can not get "SYN-ACK" package from the server. Is it the route problem? My two public interfaces do NOT have special gateway. Because I use PPPoE to connect to the Internet. So I just get ppp0 and ppp1. I don't know how to change the route table if the route table cause this problem.
However, If I do these two command on the server which is running my sever application, both commands are successful. Who can tell me why?
NOTE: I compiled this server application on Windows with cygwin. The result is the same.
Here is the code of my server application
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <unistd.h>
#define SERVPORT 3333 /* Listen Port */
#define BACKLOG 10
int main(int argc, char **argv)
{
int sockfd[2],client_fd;
struct sockaddr_in my_addr;
struct sockaddr_in remote_addr; /* client socket info */
int sin_size;
int maxfd;
fd_set rfds;
int i;
if(argc != 3)
{
printf("Usage: %s <IP_1> <IP_2>\n", argv[0]);
return 1;
}
for(i = 0; i < 2; i++)
{
if ((sockfd[i] = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket error!"); exit(1);
}
else
{
printf("Create sockfd[%d] = %d\n", i, sockfd[i]);
}
}
// set the first Socket
my_addr.sin_family=AF_INET;
my_addr.sin_port=htons(SERVPORT);
my_addr.sin_addr.s_addr = inet_addr(argv[1]);
bzero(&(my_addr.sin_zero),8);
if (bind(sockfd[0], (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) {
perror("bind error!");
exit(1);
}
// set the second Socket
my_addr.sin_family=AF_INET;
my_addr.sin_port=htons(SERVPORT);
my_addr.sin_addr.s_addr = inet_addr(argv[2]);
bzero(&(my_addr.sin_zero),8);
if (bind(sockfd[1], (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) {
perror("bind error!");
exit(1);
}
for(i = 0; i < 2; i++)
{
if (listen(sockfd[i], BACKLOG) == -1) {
perror("listen error!");
exit(1);
}
}
if(sockfd[0] > sockfd[1])
maxfd = sockfd[0];
else
maxfd = sockfd[1];
while(1) {
FD_ZERO(&rfds);
FD_SET(sockfd[0], &rfds);
FD_SET(sockfd[1], &rfds);
printf("waiting client\n");
select(maxfd + 1, &rfds, NULL, NULL, NULL);
sin_size = sizeof(struct sockaddr_in);
if(FD_ISSET(sockfd[0], &rfds))
{
printf("sockfd[0](%s) is readable\n", argv[1]);
if ((client_fd = accept(sockfd[0], (struct sockaddr *)&remote_addr, (socklen_t *)&sin_size)) == -1) {
perror("accept error");
continue;
}
}
else if(FD_ISSET(sockfd[1], &rfds))
{
printf("sockfd[1](%s) is readable\n", argv[2]);
if ((client_fd = accept(sockfd[1], (struct sockaddr *)&remote_addr, (socklen_t *)&sin_size)) == -1) {
perror("accept error");
continue;
}
}
else
{
printf("select error\n");
continue;
}
printf("received a connection from %s:%d\n\n", (char *)inet_ntoa(remote_addr.sin_addr), ntohs(remote_addr.sin_port));
if (!fork()) { /* child process */
if (send(client_fd, "Hello, you are connected!\n", 26, 0) == -1)
perror("send error!");
close(client_fd);
exit(0);
}
close(client_fd);
}
}