I am playing with SOCKS5 proxy ( TOR ). I am able to estabilish connection but now I dont know how to send and receive data to/from destination. Thanks for help. Code:
#include <stdio.h>
#include <WinSock2.h>
#include <stdlib.h>
#pragma comment(lib,"ws2_32.lib")
#define PUT_BYTE(ptr,data) (*(unsigned char*)ptr = data)
int main()
{
WORD wVersionRequested = MAKEWORD(2,0);
WSADATA wsaData;
if(WSAStartup(wVersionRequested,&wsaData) != 0 )
{
return 1;
}
int fd = socket( AF_INET, SOCK_STREAM, 0);
if (fd < 0)
return 1;
struct sockaddr_in destaddr;
destaddr.sin_addr.s_addr = inet_addr("xx.xx.xx.xx");
int dest_port = 80;
struct sockaddr_in saddr;
saddr.sin_port = htons(9150);
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = inet_addr("127.0.0.1");
int rv = connect( fd, (struct sockaddr *)&saddr, sizeof(saddr));
if(rv < SOCKET_ERROR)
return 1;
char buf[256], *ptr;
ptr = buf;
PUT_BYTE( ptr++,5);
PUT_BYTE( ptr++,1);
PUT_BYTE(ptr++,0x00);
send(fd,buf,ptr-buf,0);
recv(fd,buf,2,0);
if ( (buf[0] != 5) || buf[1] == 0xFF )
{
return 1;
}
ptr = buf;
PUT_BYTE(ptr++,5);
PUT_BYTE(ptr++,1);
PUT_BYTE(ptr++,0);
PUT_BYTE(ptr++,1);
memcpy( ptr, &destaddr.sin_addr.s_addr,sizeof(destaddr.sin_addr));
ptr += sizeof(destaddr.sin_addr);
PUT_BYTE(ptr++,dest_port>>8);
PUT_BYTE(ptr++,dest_port&0xFF);
send(fd,buf,ptr-buf,0);
recv(fd,buf,4,0);
if(buf[1] != 0x00)
{
return 1;
}
ptr = buf + 4;
switch ( buf[3] ) {
case 1:
recv( fd, ptr, 4+2,0 );
break;
case 3:
recv( fd, ptr, 1 ,0);
recv( fd, ptr+1, *(unsigned char*)ptr + 2,0);
break;
case 4:
recv( fd, ptr, 16+2,0 );
break;
}
printf("Succes!");
//How to send and receive data now? Now we are connected on port 80 and for example I want to send http get request and receive the answer.
return 0;
}
How to send and receive data now? Now we are connected on port 80 and for example I want to send http get request and receive the answer.
Once you have successfully authenticated with the proxy and told it where to connect to, then you simply send/recv your desired data (in this case, the HTTP data) using the existing connection to the proxy, as if you had connected to the target server directly and not to a proxy. Once the proxy session is established, all subsequent sends/receives are transparent to your app.
Update: You might also want to clean up your code so it is easier to read, fix your existing broken error handling, and add some additional error handling that is missing:
#include <stdio.h>
#include <WinSock2.h>
#include <stdlib.h>
#pragma comment(lib,"ws2_32.lib")
#include <pshpack1.h>
struct socks5_ident_req
{
unsigned char Version;
unsigned char NumberOfMethods;
unsigned char Methods[256];
};
struct socks5_ident_resp
{
unsigned char Version;
unsigned char Method;
};
struct socks5_req
{
unsigned char Version;
unsigned char Cmd;
unsigned char Reserved;
unsigned char AddrType;
union {
in_addr IPv4;
in6_addr IPv6;
struct {
unsigned char DomainLen;
char Domain[256];
};
} DestAddr;
unsigned short DestPort;
};
struct socks5_resp
{
unsigned char Version;
unsigned char Reply;
unsigned char Reserved;
unsigned char AddrType;
union {
in_addr IPv4;
in6_addr IPv6;
struct {
unsigned char DomainLen;
char Domain[256];
};
} BindAddr;
unsigned short BindPort;
};
#include <poppack.h>
bool sendData(SOCKET fd, void *data, int len)
{
char *ptr = (char *) data;
while (len > 0)
{
int sent = send(fd, ptr, len, 0);
if (sent <= 0)
{
printf("send() error: %d", WSAGetLastError());
return false;
}
ptr += sent;
len -= sent;
}
return true;
}
int recvData(SOCKET fd, void *data, int len, bool disconnectOk = false)
{
char *ptr = (char *) data;
int total = 0;
while (len > 0)
{
int recvd = recv(fd, ptr, len, 0);
if (recvd < 0)
{
printf("recv() error: %d", WSAGetLastError());
return -1;
}
if (recvd == 0)
{
if (disconnectOk)
break;
printf("disconnected");
return -1;
}
ptr += recvd;
len -= recvd;
total -= recvd;
}
return total;
}
bool socksLogin(SOCKET fd)
{
socks5_ident_req req;
socks5_ident_req resp;
req.Version = 5;
req.NumberOfMethods = 1;
req.Methods[0] = 0x00;
// add other methods as needed...
if (!sendData(fd, &req, 2+req.NumberOfMethods))
return false;
if (recvData(fd, &resp, sizeof(resp)) == -1)
return false;
if (resp.Version != 5)
{
printf("SOCKS v5 identification failed");
return false;
}
if (resp.Method == 0xFF)
{
printf("SOCKS v5 authentication failed");
return false;
}
/*
if (resp.Method != 0x00)
{
// authenticate as needed...
}
*/
return true;
}
bool socksRequest(SOCKET fd, const socks5_req &req, socks5_resp &resp)
{
memset(&resp, 0, sizeof(resp));
if (!sendData(fd, &req, 4))
return false;
switch (req.AddrType)
{
case 1:
{
if (!sendData(fd, &(req.DestAddr.IPv4), sizeof(in_addr)))
return false;
break;
}
case 3:
{
if (!sendData(fd, &(req.DestAddr.DomainLen), 1))
return false;
if (!sendData(fd, req.DestAddr.Domain, req.DestAddr.DomainLen))
return false;
break;
}
case 4:
{
if (!sendData(fd, &(req.DestAddr.IPv6), sizeof(in6_addr)))
return false;
break;
}
default:
{
printf("SOCKS 5 requesting unknown address type");
return false;
}
}
unsigned short port = htons(req.DestPort);
if (!sendData(fd, &port, 2))
return false;
if (recvData(fd, &resp, 4) == -1)
return false;
switch (resp.AddrType)
{
case 1:
{
if (recvData(fd, &(resp.BindAddr.IPv4), sizeof(in_addr)) == -1)
return false;
break;
}
case 3:
{
if (recvData(fd, &(resp.BindAddr.DomainLen), 1) == -1)
return false;
if (recvData(fd, resp.BindAddr.Domain, resp.BindAddr.DomainLen) == -1)
return false;
break;
}
case 4:
{
if (recvData(fd, &(resp.BindAddr.IPv6), sizeof(in6_addr)) == -1)
return false;
break;
}
default:
{
printf("SOCKS 5 bound to unknown address type");
return false;
}
}
if (recvData(fd, &port, 2, 0) == -1)
return false;
resp.BindPort = ntohs(port);
return true;
}
bool socksConnect(SOCKET fd, const in_addr &dest, unsigned short port)
{
socks5_req req;
socks5_resp resp;
req.Version = 5;
req.Cmd = 1;
req.Reserved = 0;
req.AddrType = 1;
req.DestAddr.IPv4 = dest;
req.DestPort = port;
if (!socksRequest(fd, req, resp))
return false;
if (resp.Reply != 0x00)
{
printf("SOCKS v5 connect failed, error: 0x%02X", resp.Reply);
return false;
}
return true;
}
int main()
{
WSADATA wsaData;
int rv = WSAStartup(MAKEWORD(2,0), &wsaData);
if (rv != 0)
{
printf("WSAStartup() error: %d", rv);
return 1;
}
SOCKET fd = socket( AF_INET, SOCK_STREAM, 0);
if (fd == INVALID_SOCKET)
{
printf("socket() error: %d", WSAGetLastError());
return 1;
}
struct sockaddr_in saddr;
memset(&saddr, 0, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = inet_addr("127.0.0.1");
saddr.sin_port = htons(9150);
if (connect(fd, (struct sockaddr *) &saddr, sizeof(saddr)) != 0)
{
printf("connect() error: %d", WSAGetLastError());
return 1;
}
if (!socksLogin(fd))
return 1;
if (!socksConnect(fd, inet_addr("xx.xx.xx.xx"), 80))
return 1;
printf("Success!");
// now send/receive desired data as needed using existing fd ...
return 0;
}
I wrote a modern C++ implementation for sending and receiving data through a SOCKS5 proxy server, with SOCKS5's User/Pass Authentication too (along with Anonymous mode) and also with remote and local DNS resolution options (for more privacy).
Take a look: https://github.com/harsath/SOCKS5-Proxy-Handler
(Disclaimer: I am the author of the linked repository).
Olof, the routines you are using are notoriously difficult. If your goal is to actually get something working, I would recommend that you use a tool that has been built on top of these low-level routines.
The best one is curl. At the curl website, they compare themselves with the other tools you could consider: http://curl.haxx.se/docs/comparison-table.html
Edit: all right, so you voted down my answer. Go and look at the source code for torsocks, which tries to use these routines. Compile it and try to run it. Does it work? No. Look at the source code. Try to run the test suite. Does it work? No. Look at the routines they call. Many are deprecated. Can you even figure out which routines are deprecated?
If you look around, you will see that the people who are able to actually transfer data over Tor are using curl.
Related
/.configure, make and make install
This is code for status.h
#define DEBUG(level, args...) debug(level, __location__, __FUNCTION__, args)
typedef enum {
ST_OK = 0,
ST_GENERAL_FAILURE = 1,
ST_NO_SUCH_OBJECT = 2,
ST_READ_ERROR = 3,
ST_WRITE_ERROR = 4,
ST_PARSE_ERROR = 5,
ST_LOG_ERR = 117,
ST_DATABASE_FAILURE = 118,
ST_BIND_FAILURE = 119,
ST_SOCKET_FAILURE = 120,
ST_CONFIGURATION_ERROR = 121,
ST_ASSERTION_FAILED = 122,
ST_NOT_IMPLEMENTED = 123,
ST_OUT_OF_MEMORY = 124,
} STATUS;
#define NO_MEM_RETURN(ptr) {if (ptr == NULL) { DEBUG(0, "Out of memory"); return ST_OUT_OF_MEMORY; }}
#define NO_MEM_RETURN_RV(ptr, rv) {if (ptr == NULL) { DEBUG(0, "Out of memory"); return rv; }}
STATUS debug(int loglevel, const char *location, const char *function, ...);
This is code for code for chirond.c and currently running on gcc version 4.7.2 (Debian 4.7.2-5)
#include "includes.h"
#include "build/ndr_chiron.h"
#include "build/chiron.h"
#include <nettle/md5.h>
#include <nettle/arcfour.h>
#define CHIRON_PORT "53165"
struct chiron_context {
int clientfd;
struct sockaddr *clientaddr;
char *account_code;
char *device_id;
uint8_t md5_last_out[0x10];
uint8_t rc4key[0x10];
};
/* FIXME This function is a nasty little hack. */
char *ndr_print_chiron_msg_type_enum(TALLOC_CTX *mem_ctx, enum chiron_msg_type msg_type) {
char *ret;
struct ndr_print *ndr_print = talloc_zero(mem_ctx, struct ndr_print);
ndr_print->print = ndr_print_string_helper;
ndr_print->depth = 0;
ndr_print_chiron_msg_type(ndr_print, "", msg_type);
ret = talloc_steal(mem_ctx, ndr_print->private_data);
talloc_free(ndr_print);
return ret;
}
STATUS handle_chiron_msg_response(struct chiron_context *ctx, struct chiron_message *msg) {
#if 0 // TLV, move to ASN.1 parsing
DATA_BLOB crypted, decrypted;
enum ndr_err_code ndr_err;
struct chiron_msg_inner_response *inner_response;
struct arcfour_ctx rc4;
char *deviceid_string;
if (memcmp(msg->msg.response.md5_check, ctx->md5_last_out, 0x10)) {
DEBUG(0, "MD5 does not match!\n");
return ST_PARSE_ERROR;
}
DEBUG(0, "Handling the response");
inner_response = talloc(msg, struct chiron_msg_inner_response);
NO_MEM_RETURN(inner_response);
/* Copy packet to crypted data blob */
crypted.length = msg->msg.response.length - MD5_HASH_LEN;
crypted.data = talloc_memdup(msg, msg->msg.response.payload, crypted.length);
NO_MEM_RETURN(crypted.data);
decrypted.data = talloc_array(msg, uint8_t, crypted.length);
NO_MEM_RETURN(decrypted.data);
decrypted.length = crypted.length;
arcfour_set_key(&rc4, MD5_HASH_LEN, ctx->rc4key);
arcfour_crypt(&rc4, crypted.length, decrypted.data, crypted.data);
/* Parse the packet */
ndr_err = ndr_pull_struct_blob_all(&decrypted, inner_response, inner_response, (ndr_pull_flags_fn_t)ndr_pull_chiron_msg_inner_response);
if (ndr_err != NDR_ERR_SUCCESS) {
DEBUG(0, "Could not parse the inner response");
return ST_PARSE_ERROR;
}
STATUS handle_chiron_msg_response(struct chiron_context *ctx, struct chiron_message *msg) {
#if 0 // TLV, move to ASN.1 parsing
DATA_BLOB crypted, decrypted;
enum ndr_err_code ndr_err;
struct chiron_msg_inner_response *inner_response;
struct arcfour_ctx rc4;
char *deviceid_string;
if (memcmp(msg->msg.response.md5_check, ctx->md5_last_out, 0x10)) {
DEBUG(0, "MD5 does not match!\n");
return ST_PARSE_ERROR;
}
DEBUG(0, "Handling the response");
inner_response = talloc(msg, struct chiron_msg_inner_response);
NO_MEM_RETURN(inner_response);
/* Copy packet to crypted data blob */
crypted.length = msg->msg.response.length - MD5_HASH_LEN;
crypted.data = talloc_memdup(msg, msg->msg.response.payload, crypted.length);
NO_MEM_RETURN(crypted.data);
decrypted.data = talloc_array(msg, uint8_t, crypted.length);
NO_MEM_RETURN(decrypted.data);
decrypted.length = crypted.length;
arcfour_set_key(&rc4, MD5_HASH_LEN, ctx->rc4key);
arcfour_crypt(&rc4, crypted.length, decrypted.data, crypted.data);
/* Parse the packet */
ndr_err = ndr_pull_struct_blob_all(&decrypted, inner_response, inner_response, (ndr_pull_flags_fn_t)ndr_pull_chiron_msg_inner_response);
if (ndr_err != NDR_ERR_SUCCESS) {
DEBUG(0, "Could not parse the inner response");
return ST_PARSE_ERROR;
}
DEBUG(0, "%s", ndr_print_struct_string(msg,(ndr_print_fn_t)ndr_print_chiron_msg_inner_response, "chiron payload", inner_response));
deviceid_string = talloc_zero_array(msg, char, inner_response->dev_len + 1);
memcpy(deviceid_string, inner_response->deviceid, inner_response->dev_len);
DEBUG(0, "Remote device: %s", deviceid_string);
#endif
//send_chiron_msg_key
return ST_OK;
}
STATUS send_chiron_msg_challenge(struct chiron_context *ctx, struct chiron_message *in) {
struct chiron_message *out = talloc_zero(in, struct chiron_message);
struct md5_ctx md5;
uint8_t *md5input;
enum ndr_err_code ndr_err;
DATA_BLOB raw_out;
NO_MEM_RETURN(out);
DEBUG(0, "Sending out a challenge");
out->msg_type = CHIRON_CHALLENGE;
out->seq = in->seq;
out->flags = in->flags;
/* Make an md5 hash of the account code with the seq byte appended. */
md5input = talloc_array(in, uint8_t, in->msg.account.length + 1);
NO_MEM_RETURN(md5input);
memcpy(md5input, in->msg.account.account_code, in->msg.account.length);
md5input[in->msg.account.length] = in->seq;
out->msg.challenge.md5_check = talloc_array(out, uint8_t, MD5_HASH_LEN);
NO_MEM_RETURN(out->msg.challenge.md5_check);
md5_init(&md5);
md5_update(&md5, in->msg.account.length + 1, md5input);
md5_digest(&md5, MD5_HASH_LEN, out->msg.challenge.md5_check);
talloc_free(md5input);
/* FIXME This should be random, but that is annoying for testing purposes */
out->msg.challenge.length = MD5_HASH_LEN + CHALLENGE_LEN;
out->msg.challenge.challenge = talloc_zero_array(out, uint8_t, CHALLENGE_LEN);
NO_MEM_RETURN(out->msg.challenge.challenge);
out->msg.challenge.challenge[0] = 0xd0;
out->msg.challenge.challenge[1] = 0x8b;
out->msg.challenge.challenge[2] = 0x29;
out->msg.challenge.challenge[3] = 0xd3;
out->msg.challenge.challenge[4] = 0x7c;
out->msg.challenge.challenge[5] = 0xfd;
out->msg.challenge.challenge[6] = 0xb5;
out->msg.challenge.challenge[7] = 0xc6;
out->msg.challenge.challenge[8] = 0x1e;
ndr_err = ndr_push_struct_blob(&raw_out, out, out, (ndr_push_flags_fn_t)ndr_push_chiron_message);
if (ndr_err != NDR_ERR_SUCCESS) {
DEBUG(0, "Error writing NDR data blob.");
return ST_WRITE_ERROR;
}
/* Update the md5 check for the next message (last 9 bytes with the seq byte appended). */
md5input = talloc_array(in, uint8_t, CHALLENGE_LEN + 1);
NO_MEM_RETURN(md5input);
memcpy(md5input, &raw_out.data[MSG_HDR_LEN + MD5_HASH_LEN], CHALLENGE_LEN);
md5input[CHALLENGE_LEN] = in->seq;
md5_init(&md5);
md5_update(&md5, CHALLENGE_LEN + 1, md5input);
md5_digest(&md5, MD5_HASH_LEN, ctx->md5_last_out);
/* Update the rc4 crypto key, which is seq+challenge */
md5input[0] = in->seq;
memcpy(&md5input[1], &raw_out.data[MSG_HDR_LEN + MD5_HASH_LEN], CHALLENGE_LEN);
md5_init(&md5);
md5_update(&md5, CHALLENGE_LEN + 1, md5input);
md5_digest(&md5, MD5_HASH_LEN, ctx->rc4key);
DEBUG(0, "The expected md5sum for the next entry is %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
ctx->md5_last_out[0], ctx->md5_last_out[1], ctx->md5_last_out[2], ctx->md5_last_out[3],
ctx->md5_last_out[4], ctx->md5_last_out[5], ctx->md5_last_out[6], ctx->md5_last_out[9],
ctx->md5_last_out[8], ctx->md5_last_out[9], ctx->md5_last_out[10], ctx->md5_last_out[11],
ctx->md5_last_out[12], ctx->md5_last_out[13], ctx->md5_last_out[14], ctx->md5_last_out[15]);
write(ctx->clientfd, raw_out.data, raw_out.length);
talloc_free(out);
return ST_OK;
}
STATUS handle_chiron_msg_account(struct chiron_context *ctx, struct chiron_message *msg) {
ctx->account_code = talloc_memdup(msg, msg->msg.account.account_code, msg->msg.account.length);
NO_MEM_RETURN(ctx->account_code);
send_chiron_msg_challenge(ctx, msg);
return ST_OK;
}
STATUS handle_connection(struct chiron_context *ctx) {
int n;
struct chiron_message *msg;
enum ndr_err_code ndr_err;
char buf[1024]; /* Purposefully static length */
DATA_BLOB data;
STATUS status;
DEBUG(0, "The expected md5sum for the next entry is %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
ctx->md5_last_out[0], ctx->md5_last_out[1], ctx->md5_last_out[2], ctx->md5_last_out[3],
ctx->md5_last_out[4], ctx->md5_last_out[5], ctx->md5_last_out[6], ctx->md5_last_out[9],
ctx->md5_last_out[8], ctx->md5_last_out[9], ctx->md5_last_out[10], ctx->md5_last_out[11],
ctx->md5_last_out[12], ctx->md5_last_out[13], ctx->md5_last_out[14], ctx->md5_last_out[15]);
write(ctx->clientfd, raw_out.data, raw_out.length);
talloc_free(out);
return ST_OK;
}
STATUS handle_chiron_msg_account(struct chiron_context *ctx, struct chiron_message *msg) {
ctx->account_code = talloc_memdup(msg, msg->msg.account.account_code, msg->msg.account.length);
NO_MEM_RETURN(ctx->account_code);
send_chiron_msg_challenge(ctx, msg);
return ST_OK;
}
STATUS handle_connection(struct chiron_context *ctx) {
int n;
struct chiron_message *msg;
enum ndr_err_code ndr_err;
char buf[1024]; /* Purposefully static length */
DATA_BLOB data;
STATUS status;
while ((n = read(ctx->clientfd, buf, sizeof(buf)))) {
if (n < 0) {
DEBUG( 0, "Error when storing packet in buffer!");
return ST_PARSE_ERROR;
} else if (n == sizeof(buf)) {
DEBUG(0, "Maximum packet size exceeded!");
return ST_PARSE_ERROR;
}
msg = talloc(ctx, struct chiron_message);
NO_MEM_RETURN(msg);
/* Copy packet to data blob */
data.length = n;
data.data = talloc_memdup(msg, buf, n);
NO_MEM_RETURN(data.data);
/* Parse the packet */
ndr_err = ndr_pull_struct_blob_all(&data, msg, msg, (ndr_pull_flags_fn_t)ndr_pull_chiron_message);
if (ndr_err != NDR_ERR_SUCCESS) {
DEBUG(0, "Could not parse this message");
return ST_PARSE_ERROR;
}
DEBUG(0, "%s", ndr_print_struct_string(msg,(ndr_print_fn_t)ndr_print_chiron_message, "chiron message", msg));
switch (msg->msg_type) {
case CHIRON_ACCOUNT:
status = handle_chiron_msg_account(ctx, msg);
break;
case CHIRON_RESPONSE:
status = handle_chiron_msg_response(ctx, msg);
break;
default:
DEBUG(0, "Got unexpected message type: %s.",
ndr_print_chiron_msg_type_enum(msg, msg->msg_type));
break;
}
if (status != ST_OK) {
return status;
}
talloc_free(msg);
}
return ST_OK;
}
static STATUS daemonize(char *pid_file) {
FILE *pidfile;
pid_t pid;
fclose(stdin);
fclose(stdout);
fclose(stderr);
if ((pid = fork())) {
/* Write PID file */
pidfile = fopen(pid_file, "w");
if (pidfile < 0)
exit(1);
fprintf(pidfile, "%d\n", pid);
fclose(pidfile);
exit(0);
}
return ST_OK;
}
static STATUS listen_server(TALLOC_CTX *mem_ctx, const char *bindaddr, const char *bindport, const char *protocol, STATUS (*dispatcher)(struct chiron_context *)) {
int sock;
socklen_t clientlen;
struct addrinfo hints, *server, *first_server;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_flags = AI_PASSIVE;
getaddrinfo(bindaddr, bindport, &hints, &server);
first_server = server;
while (server) {
sock = socket(server->ai_family, SOCK_STREAM, 0);
if (sock >= 0) {
int optval = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
if (bind(sock, server->ai_addr, server->ai_addrlen) < 0) {
close(sock);
sock = -1;
} else {
{
break;
}
}
server = server->ai_next;
}
if (sock < 0) {
DEBUG(0, "Could not create socket in server");
return ST_SOCKET_FAILURE;
}
listen(sock, 128);
freeaddrinfo(first_server);
DEBUG(0, "Started %s and waiting for Chiron messages on port %s",
get_process_name(), CHIRON_PORT);
/*
* Wait for connections
*/
clientlen = sizeof(struct addrinfo);
while (1) {
int clientfd;
struct sockaddr_storage clientaddr;
char clienthost[NI_MAXHOST];
char clientservice[NI_MAXSERV];
clientfd = accept(sock, (struct sockaddr *)&clientaddr, &clientlen);
getnameinfo((struct sockaddr *)&clientaddr, clientlen,
clienthost, sizeof(clienthost),
clientservice, sizeof(clientservice),
NI_NUMERICHOST | NI_NUMERICSERV);
DEBUG(3, "Received connection from %s:%s", clienthost, clientservice);
//if (fork()) {
// continue;
//} else {
{
struct chiron_context *client_ctx = talloc_zero(mem_ctx, struct chiron_context);
NO_MEM_RETURN(client_ctx);
client_ctx->clientaddr = (struct sockaddr *)&clientaddr;
client_ctx->clientfd = clientfd;
dispatcher(client_ctx);
shutdown(client_ctx->clientfd, SHUT_RDWR);
close(client_ctx->clientfd);
talloc_free(client_ctx);
exit(0);
}
}
shutdown(sock, SHUT_RDWR);
close(sock);
}
int main (int argc, char **argv) {
TALLOC_CTX *mem_ctx;
STATUS rv;
const configuration *conf;
set_process_name(argv[0]);
/* Initialize a memory context */
mem_ctx = talloc_init("chirond");
/* Read the configuration file */
rv = read_configuration_file(mem_ctx);
if (rv != ST_OK)
return rv;
conf = get_conf();
/* Daemonize if we're not supposed to run in foreground mode */
if (!conf->foreground) {
daemonize(conf->pid_file);
}
/*
* Open up a TCP socket the Chiron port
*/
listen_server(mem_ctx, "::", CHIRON_PORT, "tcp", handle_connection);
return 0;
}
getting error on make, ISO c does not permit named variadic macros on ubutnu
In file included from ../includes.h:43:0,
from ../chirond.c:18:
../status.h:19:26: error: ISO C does not permit named variadic macros [-Werror=variadic-macros]
Have to upgrade GCC to 4.9 and if you are to lower version using follow instructions on this page.
[https://solarianprogrammer.com/2015/01/13/raspberry-pi-raspbian-install-gcc-compile-cpp-14-programs/][1]
put this lines to avoid warnings
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wvariadic-macros"
// Your code and/or include files
// (No variadic warnings here)
#pragma GCC diagnostic pop
if you have so much warnings remove -werror from CFLAGS. you can able to build.
I have some problem.
I write next code.
z=recv(conn,buff,512,0);//"Hi VahagnAAAAAAA" - but encrypted for example "zЖWЙЇ%ЂАЊ"S]яАAЧ0АбЯ.Щk5S¤Oц", length 32
BYTE messageLen = (BYTE)strlen(buff);// messageLen = 32
BYTE encryptedMessage[32];
memcpy(encryptedMessage, buff, messageLen);//!!!!!!!!!!!
DWORD encryptedMessageLen = messageLen;
CryptDecrypt(hSessionKeyRSA_2,NULL,TRUE,0,encryptedMessage, &encryptedMessageLen);
cout<<encryptedMessage<<endl;
I recv to buffer char array 32 length.
Where I copy encrypted text
"zЖWЙЇ%ЂАЊ"S]яАAЧ0АбЯ.Щk5S¤Oц"
to byte array, on the encryptedMessage have next value
"zЖWЙЇ%ЂАЊ"S]яАAЧ0АбЯ.Щk5S¤OцMMMMMMMMMMMMMMMMMMM"
where I decrypted I don't get start text, I get
"Ik VqagnеAAcS]‰МММММММММММ ММММММММ"
How I can fix it? please help me.
UPDATE
Client main()
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
const char* servername="127.0.0.1";
Sleep(2000);
setlocale(LC_ALL, "Russian");
WSADATA wsaData;
struct hostent *hp;
unsigned int addr;
struct sockaddr_in server;
int wsaret=WSAStartup(0x101,&wsaData);
if(wsaret)
return 0;
SOCKET conn;
conn=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(conn==INVALID_SOCKET)
return 0;
if(inet_addr(servername)==INADDR_NONE)
{
hp=gethostbyname(servername);
}
else
{
addr=inet_addr(servername);
hp=gethostbyaddr((char*)&addr,sizeof(addr),AF_INET);
}
if(hp==NULL)
{
closesocket(conn);
return 0;
}
server.sin_addr.s_addr=*((unsigned long*)hp->h_addr);
server.sin_family=AF_INET;
server.sin_port=htons(20248);
if(connect(conn,(struct sockaddr*)&server,sizeof(server)))
{
closesocket(conn);
return 0;
}
std::cout<<"Connected to server";
char buff[512];
memset(buff,'\0',512);
int z;
z=recv(conn,(char*)exportRSAKey,140,0);//Import RSA key
z=recv(conn,(char*)exportAESKey,140,0);//Import AES key
z=recv(conn,buff,512,0);//Get encryption text
importKey();//import key to client
BYTE messageLen = (BYTE)strlen(buff);
BYTE encryptedMessage[33];
memcpy(encryptedMessage, buff, messageLen);
DWORD encryptedMessageLen = messageLen;
CryptDecrypt(hSessionKeyRSA_2,NULL,FALSE,0,encryptedMessage, &encryptedMessageLen);
cout<<encryptedMessage<<endl;
// buff[z]=0;
}
Import key to client
if (CryptAcquireContext(&hCryptProv_RSA_2, NULL, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, 0))
{
printf("A cryptographic provider has been acquired.\r\n");
}
else
{
DWORD d = GetLastError();
return -1;
}
int iii = CryptImportKey(hCryptProv_RSA_2,(BYTE *)&exportAESKey,140,NULL,NULL,&hSessionKeyRSA_2);
if(CryptSetKeyParam(hSessionKeyRSA_2, KP_IV, exportRSAKey, 0))
{
cout<<"ok";
}
Server main()
std::cout<<"Client connected... "<<pParam<<std::endl;
char buff[512];
CString cmd;
CString params;
int n;
int x;
BOOL auth=false;
SOCKET client=(SOCKET)pParam;
strcpy(buff,"#Server Ready.\r\n");
char keybuff[1024];
createRSAPublicKey();//create enc_dec key
//keybuff = exportRSAKey;
//memset(rec,'\0',512);
const char *p = reinterpret_cast<const char*>(exportRSAKey);
send(client,p,140,0);//send RSA
const char *pp = reinterpret_cast<const char*>(exportAESKey);
send(client,pp,140,0);//Send AES
const char *ppp = reinterpret_cast<const char*>(encryptedMessage);
send(client,ppp,512,0);//Send encrypt text
createRSAPublicKey()
BOOL createRSAPublicKey()
{
if (CryptAcquireContext(&hCryptProv_AES, NULL, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, 0))
{
printf("A cryptographic provider has been acquired.\r\n");
}
else
{
DWORD d = GetLastError();
return -1;
}
HCRYPTKEY hSessionKey_AES;
if (!CryptGenKey(hCryptProv_AES, CALG_AES_256, CRYPT_EXPORTABLE, &hSessionKey_AES))
{
DWORD d = GetLastError();
return -1;
}
// Create RSA key to encrypt AES one
HCRYPTKEY hSessionKey;
if (!CryptGenKey(hCryptProv_AES, AT_KEYEXCHANGE, 1024 << 16, &hSessionKey))
{
DWORD d = GetLastError();
return -1;
}
// Export key
DWORD keylen;
BOOL ok = CryptExportKey(hSessionKey_AES, hSessionKey, SIMPLEBLOB, 0, exportRSAKey, &keylen);
if (ok == FALSE)
{
DWORD d = GetLastError();
return -1;
}
BYTE *encKey = (BYTE *)malloc(keylen);
ok = CryptExportKey(hSessionKey_AES, hSessionKey, SIMPLEBLOB, 0, exportAESKey, &keylen);
if (ok == FALSE)
{
DWORD d = GetLastError();
return -1;
}
else
printf("A cryptographic key export succeeded.\r\n");
BYTE messageLen = (BYTE)strlen(mess);
memcpy(encryptedMessage, mess, messageLen);
DWORD encryptedMessageLen = messageLen;
CryptEncrypt(hSessionKey_AES, NULL, TRUE, 0, encryptedMessage, &encryptedMessageLen, sizeof(encryptedMessage));
}
You are using strlen() to get the length of buff, but recv() does not null-terminate the buffer unless a null terminator was actually transmitted and read. You should instead be using the return value of recv(), which is the number of bytes actually read:
z=recv(conn,buff,512,0);
messageLen = z;//(BYTE)strlen(buff);
That being said, TCP is a byte stream, it has no concept of message boundaries. There is no 1-to-1 relationship between send() and recv() in TCP, like there is in UDP, so recv() above could read as little as 1 byte or as many as 512 bytes, and buff could contain a full message, a partial message, pieces of multiple messages, etc. You can't just blindly read and expect to receive everything in one go. You need to take all of that into account.
Design your TCP protocol to delimit messages, either with a preceding header that specifies the message length, or a trailing delimiter that never appears in the message body. Call recv() as many times as it takes, buffering any received data, and only process/decrypt complete messages that are in your buffer, leaving partial message data in the buffer to be completed by later reads.
Try something more like this:
Client main()
int readBuffer(SOCKET s, void *buffer, int buflen)
{
unsigned char *pbuf = (unsigned char*) buffer;
int total = 0;
while (total < buflen)
{
int num = recv(s, pbuf+total, buflen-total, 0);
if (num < 0)
return SOCKET_ERROR;
if (num == 0)
return 0;
total += num;
}
return total;
}
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
const char* servername="127.0.0.1";
setlocale(LC_ALL, "Russian");
WSADATA wsaData;
memset(&wsaData, 0, sizeof(wsaData));
int wsaret = WSAStartup(0x101, &wsaData);
if (wsaret != 0)
return 0;
struct sockaddr_in server;
memset(&server, 0, sizeof(server));
server.sin_addr.s_addr = inet_addr(servername);
if (server.sin_addr.s_addr == INADDR_NONE)
{
struct hostent *hp = gethostbyname(servername);
if (hp == NULL)
return 0;
server.sin_addr = *((in_addr*)hp->h_addr);
}
server.sin_family = AF_INET;
server.sin_port = htons(20248);
SOCKET conn = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (conn == INVALID_SOCKET)
return 0;
if (connect(conn, (struct sockaddr*)&server, sizeof(server)) != 0)
{
closesocket(conn);
return 0;
}
std::cout << "Connected to server";
if (readBuffer(conn, exportRSAKey, 140) <= 0) //Import RSA key
{
closesocket(conn);
return 0;
}
if (readBuffer(conn, exportAESKey, 140) <= 0) //Import AES key
{
closesocket(conn);
return 0;
}
importKey();//import key to client
DWORD messageLen;
if (readBuffer(conn, &messageLen, sizeof(messageLen)) <= 0) //Get encryption text length
{
closesocket(conn);
return 0;
}
messageLen = ntohl(messageLen);
std::vector<BYTE> buff(messageLen);
if (messageLen > 0)
{
if (readBuffer(conn, &buff[0], messageLen) <= 0) //Get encryption text
{
closesocket(conn);
return 0;
}
if (!CryptDecrypt(hSessionKeyRSA_2, NULL, FALSE, 0, &buff[0], &messageLen))
{
closesocket(conn);
return 0;
}
}
std::cout << std::string((char*)buff.data(), messageLen) << std::endl;
}
Server main()
int sendBuffer(SOCKET s, void *buffer, int buflen)
{
unsigned char *pbuf = (unsigned char*) buffer;
int total = 0;
while (total < buflen)
{
int num = send(s, pbuf+total, buflen-total, 0);
if (num < 0)
return SOCKET_ERROR;
if (num == 0)
return 0;
total += num;
}
return total;
}
...
SOCKET client = (SOCKET)pParam;
std::cout << "Client connected... " << pParam << std::endl;
...
createRSAPublicKey();//create enc_dec key
...
if (sendBuffer(client, exportRSAKey, 140) <= 0) //send RSA
{
closesocket(client);
return;
}
if (sendBuffer(client, exportAESKey, 140) <= 0) //Send AES
{
closesocket(client);
return;
}
...
DWORD tmpMessageLen = htonl(messageLen);
if (sendBuffer(client, &tmpMessageLen, sizeof(tmpMessageLen)); //Send encrypt text length
{
closesocket(client);
return;
}
if (sendBuffer(client, encryptedMessage, messageLen) <= 0) //Send encrypt text
{
closesocket(client);
return;
}
...
I'm trying to send the large amount of data to the server which should accept the data and parse it. So as I know, when you send() the data in blocking mode in one call, it splits data into chunks and then sends the chunks to the target. But I need to mark each chunk with a small identifier in the beginning of the data (let's say I'm placing a header in each chunk), so I decided to use non- blocking send. I thought, when I do non-blocking send, it sends the max the buffer allows and then returns, leaving the chunking work for me, but it seems that's not happening.
My code is:
struct sockaddr_in target;
SOCKET connection = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
target.sin_family = AF_INET;
target.sin_addr.s_addr = inet_addr(host);
target.sin_port = htons(port);
ULONG NonBlock;
NonBlock = 1;
if (ioctlsocket(connection, FIONBIO, &NonBlock) == SOCKET_ERROR)
{
return WSAGetLastError();
}
fd_set write_fds;
FD_ZERO(&write_fds);
FD_SET(connection, &write_fds);
struct timeval tv;
tv.tv_sec=1;
tv.tv_usec=0;
int result = connect(connection,(SOCKADDR*)&target,sizeof(target));
if(result==SOCKET_ERROR)
{
while(true)
{
result= select(connection+1,NULL,&write_fds,NULL,&tv);
printf("connect: result=%d\r\n",result);
if(result== -1)
{
return WSAGetLastError();
}
else break;
}
}
//later on
fd_set write_set;
int bytes_sent= 0;
int total_sent = 0;
int length = 0;
char *tmp = malloc(sizeof(header)+data_size); //data_size is the size of the large buffer
memcpy(tmp,packet,sizeof(header));
memcpy(tmp+sizeof(header),data,data_size);
int result;
FD_ZERO(&write_set);
FD_SET(connection,&write_set);
struct timeval time_out;
time_out.tv_sec=0;
time_out.tv_usec=1500;
while(total_sent < data_size)
{
length= (data_size+sizeof(my_header))-total_sent;
result = select(connection+1,NULL,&write_set,NULL,&time_out);
if(result== SOCKET_ERROR) return -1;
if(result!=0 && FD_ISSET(connection, &write_set))
{
bytes_sent = send(connection,tmp,length,0);
}
if(bytes_sent == SOCKET_ERROR)
{
return SOCKET_ERROR;
}
if(bytes_sent > 0)
{
//here i need to append a header to the new chunk
}
else break;
}
So basically my question is: why the send on non-blocking socket, still blocks and doesn't return after sending the first chunk, and acts just like regular blocking send? What i want to achieve is send() sending one chunk of data of the length that the system allows, so i put the length of the whole data, assuming that non-blocking send will return after sending the first chunk, because the buffer is to big, to be sent as one block.
UPDATE some runnable code:
#include <windows.h>
#include <winsock.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <types.h>
typedef struct hdr{
uint8_t super_id;
}my_header,*pmy_header;
SOCKET connection;
int start_winsock()
{
WSADATA check;
int result = WSAStartup(MAKEWORD(2,2),&check);
return result;
}
int create_connection(char* host,int port)
{
struct sockaddr_in target;
connection = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
target.sin_family = AF_INET;
target.sin_addr.s_addr = inet_addr(host);
target.sin_port = htons(port);
int result = UnblockSocket();
if(result!=0) return WSAGetLastError();
fd_set write_fds;
FD_ZERO(&write_fds);
FD_SET(connection, &write_fds);
struct timeval tv;
tv.tv_sec=1;
tv.tv_usec=0;
result = connect(connection,(SOCKADDR*)&target,sizeof(target));
if(result==SOCKET_ERROR)
{
while(true)
{
result= select(connection+1,NULL,&write_fds,NULL,&tv);
if(result== -1)
{
return WSAGetLastError();
}
else break;
}
}
return 0;
}
int UnblockSocket()
{
ULONG NonBlock;
NonBlock = 1;
if (ioctlsocket(connection, FIONBIO, &NonBlock) == SOCKET_ERROR)
{
return WSAGetLastError();
}
return 0;
}
int SendMyData(pmy_header header,char * data,int data_size)
{
fd_set write_set;
int bytes_sent= 0;
int total_sent = 0;
int length = 0;
char *tmp = malloc(sizeof(my_header)+data_size);
memcpy(tmp,packet,sizeof(my_header));
memcpy(tmp+sizeof(my_header),data,data_size);
int result;
FD_ZERO(&write_set);
FD_SET(connection,&write_set);
struct timeval time_out;
time_out.tv_sec=0;
time_out.tv_usec=1500;
header->super_id=0xdead;
while(total_sent < data_size)
{
length= (data_size+sizeof(my_header))-total_sent;
if(result== SOCKET_ERROR) return -1;
if(result!=0 && FD_ISSET(connection, &write_set))
{
bytes_sent = send(connection,tmp,length,0);
}
printf("bytes sent per iteration=%d\n",bytes_sent);
if(bytes_sent == SOCKET_ERROR)
{
return SOCKET_ERROR;
}
if(bytes_sent > 0)
{
total_sent+= bytes_sent-sizeof(my_header);
tmp = realloc(tmp,sizeof(my_header)+(data_size-total_sent));
memcpy(tmp,header,sizeof(my_header));
memcpy(tmp+sizeof(my_header),data,data_size-total_sent);
}
else break;
}
free(tmp);
return total_sent;
}
int main(int argc, char *argv[])
{
start_winsock();
int result = create_connection("2.2.2.2",88);
if(result!=0) { printf("Cannot connect\n"); return 0; }
pmy_header *header = malloc(sizeof(my_header));
int buf_size = 500000;
char buffer_test[buf_size];
ZeroMemory(buffer_test,buf_size);
int count=0;
for(count;count<buf_size;count++)
{
strcat(buffer_test,"4");
}
result = SendMyData(header,buffer_test,buf_size);
}
send() is not guaranteed to send everything you ask it to send. It may send less. You MUST take the return value into account. If it is less than the amount you requested, you have to call send() again to re-send the remaining bytes, before then sending new bytes. And in the case of non-blocking, you have to take WSAEWOULDBLOCK into account as well.
And you don't put on a header on each chunk that send() sends. You put a header on each chunk you tell send() to send. You do your own chunking, don't worry about the chunking that TCP does internally. That is a network implementation, it does not affect your protocol. The receiver should be paying attention to your chunk headers, calling recv() as many times as needed to receive your full header and data to account for TCPs chunking.
Try something more like this instead:
SOCKET connection = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (connection == INVALID_SOCKET)
{
return WSAGetLastError();
}
ULONG NonBlock = 1;
in result = ioctlsocket(connection, FIONBIO, &NonBlock);
if (result == SOCKET_ERROR)
{
result = WSAGetLastError();
closesocket(connection);
return result;
}
struct sockaddr_in target;
memset(&target, 0, sizeof(target));
target.sin_family = AF_INET;
target.sin_addr.s_addr = inet_addr(host);
target.sin_port = htons(port);
result = connect(connection, (SOCKADDR*)&target, sizeof(target));
if (result == SOCKET_ERROR)
{
result = WSAGetLastError();
if (result != WSAEWOULDBLOCK)
{
closesocket(connection);
return result;
}
fd_set write_fds;
FD_ZERO(&write_fds);
FD_SET(connection, &write_fds);
struct timeval tv;
tv.tv_sec = 5;
tv.tv_usec = 0;
result = select(0, NULL, &write_fds, NULL, &tv);
if (result == SOCKET_ERROR)
{
result = WSAGetLastError();
closesocket(connection);
return result;
}
if (result == 0)
{
closesocket(connection);
return WSAETIMEDOUT;
}
}
char *tmp_data = data;
int data_remaining = data_size;
while (data_remaining > 0)
{
int pkt_data_size = min(data_remaining, 1024); // replace 1024 with whatever maximum chunk size you want...
int pkt_size = sizeof(header) + pkt_data_size;
char *pkt = malloc(pkt_size);
if (!pkt) return -1;
// fill header as needed...
memcpy(pkt+sizeof(header), tmp_data, pkt_data_size);
tmp_data += pkt_data_size;
data_remaining -= pkt_data_size;
char *tmp_pkt = pkt;
while (pkt_size > 0)
{
result = send(connection, tmp_pkt, pkt_size, 0);
if (result == SOCKET_ERROR)
{
result = WSAGetLastError();
if (result != WSAEWOULDBLOCK)
{
free(pkt);
return -1;
}
fd_set write_set;
FD_ZERO(&write_set);
FD_SET(connection, &write_set);
struct timeval time_out;
time_out.tv_sec = 5;
time_out.tv_usec = 0;
result = select(0, NULL, &write_set, NULL, &time_out);
if (result != 1)
{
free(pkt);
return -1;
}
continue;
}
tmp_pkt += result;
pkt_size -= result;
}
free(pkt);
}
I am trying to capture only packets from a specific interface and instead I am getting packets from all of the interfaces. what am I doing wrong?
bool Snooper::raw_init (const char *device)
{
uid_t privid = geteuid();
int retval;
bool retVal = false;
do {
if ((retval = setuid(0)) != 0) {
perror("seteuid error");
break;
}
cap_t caps = cap_get_proc();
cap_value_t cap_list[2];
cap_list[0] = CAP_NET_RAW;
cap_list[1] = CAP_SETUID;
if ((retval = cap_set_flag(caps, CAP_EFFECTIVE, 2, cap_list, CAP_SET)) == -1) {
perror("cap_set_flag error");
break;
}
if ((retval = cap_set_proc(caps)) == -1) {
perror("cap_set_proc error");
break;
}
struct ifreq ifr;
memset(&ifr, 0, sizeof (struct ifreq));
/* Open A Raw Socket */
if ((m_sockfd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_ALL))) < 1) {
perror("Snooper::raw_init:socket Error");
break;
}
/* Set the device to use */
strncpy(ifr.ifr_name, device, strlen(device) + 1);
/* Get the current flags that the device might have */
if (ioctl(m_sockfd, SIOCGIFFLAGS, &ifr) == -1) {
perror("Error: Could not retrieve the flags from the device.\n");
break;
}
printf("The interface is ::: %s\n", device);
perror("Retrieved flags from interface successfully");
/* Set the old flags plus the IFF_PROMISC flag */
ifr.ifr_flags |= IFF_PROMISC;
if (ioctl(m_sockfd, SIOCSIFFLAGS, &ifr) == -1) {
perror("Error: Could not set flag IFF_PROMISC");
break;
}
printf("Setting interface ::: %s ::: to promisc\n", device);
/* Configure the device */
if (ioctl(m_sockfd, SIOCGIFINDEX, &ifr) < 0) {
perror("Error: Error getting the device index.\n");
break;
}
retVal = true;
} while(false);
if ((retval = seteuid(privid)) != 0) {
perror("seteuid error");
}
return retVal;
}
I first validate that I can suid to root since IFF_PROMISC requires it. Then create the socket for UDP traffic, preform the IOCtl for the device, and finally IOCtl for PROMISC.
Now that I have a socket ready I loop on a recv, however I get packets from the other interfaces as well.
To capture packets from a specific interface, you have to bind your socket to that interface using bind function. You can check out this answer for an example.
A small pcap Program that might be able to help You
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<pcap/pcap.h>
#include<netinet/if_ether.h>
#include<netinet/ip.h>
#include<netinet/tcp.h>
void process_packet(u_char *args, const struct pcap_pkthdr *header,
const u_char *buffer)
{
// printf("In Process_Packet\n");
struct ethhdr *eth = (struct ethhdr *)(buffer);
printf("%.2x: %.2x: %.2x: %.2x: %.2x: %.2x: %.2x:\n ", eth->h_dest[0], eth->h_dest[1], eth->h_dest[2], eth->h_dest[3], eth->h_dest[4], eth->h_dest[5], eth->h_dest[6]);
printf("%x \n", htons(eth->h_proto));
if(htons(eth->h_proto)== ETHERTYPE_ARP)
{
printf("ARP PACKET\n");
}
struct iphdr *iph = (struct iphdr*)(buffer + sizeof(struct ethhdr));
int ipheader = iph-> ihl *4;
printf("Source IP Address :%s\n ", inet_ntoa(iph->saddr));
printf("Destination IP Address :%s\n ", inet_ntoa(iph->daddr));
}
int main()
{
pcap_if_t *alldevspec,*devices;
pcap_addr_t *a;
pcap_t *handle;
const char filter_exp[]="IP";
bpf_u_int32 netp;
char errbuf[PCAP_ERRBUF_SIZE];
struct bpf_program fp;
int ret=0, count =1, n=0;
char devs[100][100],*devicename;
ret = pcap_findalldevs(&alldevspec,errbuf);
if(ret < 0)
{
printf("Error in finding the devices\n");
return -1;
}
for(devices = alldevspec; devices!= NULL; devices = devices->next)
{
printf("%d %s-%s \n",count, devices->name,devices->description);
for(a=devices->addresses;a;a=a->next)
{
printf("family %d \n", (a->addr)->sa_family);
if(devices->name != NULL)
{
strcpy(devs[count], devices->name);
}
switch((a->addr)->sa_family)
{
case AF_INET:
printf("%s \n",inet_ntoa(((struct sockaddr_in*)a->addr)->sin_addr.s_addr));
break;
case AF_INET6:
break;
}
}
++count;
}
printf("Enter the device u want to select\n");
scanf("%d",&n);
devicename = devs[n];
handle = pcap_open_live(devicename,65536,1,-1,errbuf);
if(handle == NULL)
{
printf("Error in opening the device\n");
return -1;
}
pcap_compile(handle,&fp, filter_exp,-1,netp);
pcap_setfilter(handle, &fp);
pcap_loop(handle,-1,process_packet,NULL);
return 0;
}
I have to make an app using C sockets on Mac-OS that sends data from one socket to other socket, like this.
Server waits for connections
Client connect to server(from 1). -> socket1
Server connects to an external server and obtains an socket. -> socket2
From now on the server job is finish. The data exchange should be made only between the client socket (from 2) and socket obtained from 3.
Current implementation:
Server makes the connection and then reads data from one socket and sends to other.
Any ides how after step 3 to pipe line the two sockets socket1 and socket2.
Well your problem can be solved in two ways:
1) You need to code the part related to the connection formation between client and external server. But this puts an extra overload on the client, because it needs to make two connections, to both the servers (and I strongly feel the middle server in this case is useless).
2) Second way of solving it is passing the sockets between the servers:
Client connects to the server, this middle server sends this socket to the external server. Now external server starts communication with the client. This can be done only if both the server processes run on the same machine. And the file-descriptors are usually passed using Unix Domain Sockets.
Here is the code which I have. You can use these two functions to either send or receive the file-descriptors. It works on my Linux machine. I don't know about Mac-OS.
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/uio.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
/* this function passes 'fd_to_send'
file descriptor via
a unix domain socket 'sfd'...
*/
void pass_fd(int sfd, int fd_to_send)
{
struct msghdr msg;
/*allocate memory to 'msg_control' field in msghdr struct */
char buf[CMSG_SPACE(sizeof(int))];
/*the memory to be allocated should include data + header..
this is calculated by the above macro...(it merely adds some
no. of bytes and returs that number..*/
struct cmsghdr *cmsg;
struct iovec ve;
/*must send/receive atleast one byte...
main purpose is to have some error
checking.. but this is completely
irrelevant in the current context..*/
char *st ="I";
/*jst let us allocate 1 byte for formality
and leave it that way...*/
ve.iov_base = st;
ve.iov_len =1;
/*attach this memory to our main msghdr struct...*/
msg.msg_iov = &ve;
msg.msg_iovlen = 1;
/*these are optional fields ..
leave these fields with zeros..
to prevent unnecessary SIGSEGVs..*/
msg.msg_name = NULL;
msg.msg_namelen = 0;
/*here starts the main part..*/
/*attach the 'buf' to msg_control..
and fill in the size field correspondingly..
*/
msg.msg_control = buf;
msg.msg_controllen = sizeof(buf);
/*actually msg_control field must
point to a struct of type 'cmsghdr'
we just allocated the memory, yet we need to
set all the corresponding fields..
It is done as follows:
*/
cmsg = CMSG_FIRSTHDR(&msg);
/* this macro returns the address in the buffer..
from where the first header starts..
*/
/*set all the fields appropriately..*/
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof(fd_to_send));
/*in the above field we need to store
the size of header + data(in this case 4 bytes(int) for our fd..
this is returned by the 'CMSG_LEN' macro..*/
*(int*)CMSG_DATA(cmsg) = fd_to_send;
/*after the above three fields we keep the actual data..
the macro 'CMSG_DATA' returns pointer to this location
and we set it to the file descriptor to be sent..
*/
msg.msg_controllen = cmsg->cmsg_len;
/*now that we have filled the 'cmsg' struct
we store the size of this struct..*/
/*this one isn't required when you
pass a single fd..
but useful when u pass multiple fds.*/
msg.msg_flags = 0;
/*leave the flags field zeroed..*/
if(sendmsg( sfd, &msg, 0)==-1){ perror("snd:\n"); exit(1); }
/*send this over the UNIX deomain socoket..*/
printf("sent fd:%d\n", fd_to_send);
close(fd_to_send);
/*close the fd which was sent..*/
}
/*returns the received fd over the unix domain socket 'sfd'..*/
int recv_fd(int sfd)
{
struct msghdr msg;
/*do all the unwanted things first...
same as the send_fd function..*/
struct iovec io;
char ptr[1];
io.iov_base = ptr;
io.iov_len = 1;
msg.msg_name = 0;
msg.msg_namelen = 0;
msg.msg_iov = &io;
msg.msg_iovlen = 1;
/*-----------------------*/
char buf[CMSG_SPACE(sizeof(int))];
msg.msg_control = buf;
msg.msg_controllen = sizeof(buf);
/*reasoning is same..as above*/
/*now here comes the main part..*/
if(recvmsg( sfd, &msg, 0)==-1)
{
/*some shit has happened*/
perror("recv\n");
exit(1);
}
struct cmsghdr *cm;
cm = CMSG_FIRSTHDR(&msg);
/*get the first message header..*/
if(cm->cmsg_type != SCM_RIGHTS)
{
/*again some shit has happened..*/
perror("unknown type..\n");
exit(1);
}
/*if control has reached here.. this means
we have got the correct message..and when you
extract the fd out of this message
this need not be same as the one which was sent..
allocating a new fd is all done by the kernel
and our job is jst to use it..*/
printf("received fd:%d\n", *(int*)CMSG_DATA(cm));
return *(int*)CMSG_DATA(cm);
}
In the below example:
ClientOne and ClientTwo connect to the server.
When the server receives both ClientOne and ClientTwo's socket descriptor, it sends ClientOne's information to ClientTwo and vice-versa.
The information it sends is the IP and the client is coming from. Server shuts down.
When each client receives their info, a socket is created and they connect to eachother. The server socket is then shutdown.
Socket Class:
#include <winsock2.h>
#include <Ws2tcpip.h>
#include <windows.h>
#include <cstdint>
#include <string>
#include <stdexcept>
#include <iostream>
#include <thread>
#include <vector>
class Socket
{
private:
SOCKET socket;
std::uint32_t Port;
std::string Address;
bool Listen, Initialized, Asynchronous;
void Swap(Socket &S);
void UnInitialized();
public:
Socket();
Socket(std::uint32_t Port, std::string Address, bool Listen = false, bool Asynchronous = false);
Socket(const Socket &S) = delete;
Socket(Socket && S);
~Socket();
Socket& operator = (const Socket &S) = delete;
Socket& operator = (Socket && S);
int Recv(void* Buffer, std::uint32_t BufferLength);
int Recv(SOCKET S, void* Buffer, std::uint32_t BufferLength);
std::uint32_t RecvEx(void* Buffer, std::uint32_t BufferLength);
std::uint32_t RecvEx(SOCKET S, void* Buffer, std::uint32_t BufferLength);
int Send(void* Buffer, std::size_t BufferSize);
int Send(SOCKET S, void* Buffer, std::size_t BufferSize);
void Connect();
void Connect(std::uint32_t Port, std::string Address, bool Listen, bool Asynchronous);
SOCKET Accept(sockaddr* ClientInfo, int* ClientInfoSize);
void Close();
SOCKET GetSocket() const;
};
Socket::~Socket()
{
Close();
}
void Socket::Close()
{
if (socket)
{
shutdown(socket, SD_BOTH);
closesocket(socket);
socket = 0;
}
if (Initialized)
{
WSACleanup();
}
}
SOCKET Socket::GetSocket() const
{
return this->socket;
}
Socket::Socket(Socket && S) : socket(std::move(S.socket)), Port(std::move(S.Port)), Address(std::move(S.Address)), Listen(std::move(S.Listen)), Initialized(std::move(S.Initialized)), Asynchronous(std::move(S.Asynchronous)) {}
Socket::Socket() : socket(0), Port(0), Address(std::string()), Listen(false), Initialized(false), Asynchronous(false) {}
Socket::Socket(std::uint32_t Port, std::string Address, bool Listen, bool Asynchronous) : socket(0), Port(Port), Address(Address), Listen(Listen), Initialized(true), Asynchronous(Asynchronous)
{
Connect(Port, Address, Listen, Asynchronous);
}
void Socket::Connect()
{
UnInitialized();
Connect(Port, Address, Listen, Asynchronous);
}
void Socket::Connect(std::uint32_t Port, std::string Address, bool Listen, bool Asynchronous)
{
if (!socket)
{
this->Port = Port;
this->Address = Address;
this->Asynchronous = Asynchronous;
this->Initialized = true;
WSADATA wsaData;
struct sockaddr_in* sockaddr_ipv4;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
throw std::runtime_error("Error: WSAStartup Failed");
}
if (Address != "INADDR_ANY")
{
if (Address.find("http://") != std::string::npos)
{
Address = Address.substr(7);
}
std::size_t Position = Address.find("/");
if (Position != std::string::npos)
{
Address = Address.substr(0, Position);
}
struct addrinfo *it = nullptr, *result = nullptr;
getaddrinfo(Address.c_str(), nullptr, nullptr, &result);
for (it = result; it != nullptr; it = it->ai_next)
{
sockaddr_ipv4 = reinterpret_cast<sockaddr_in*>(it->ai_addr);
Address = inet_ntoa(sockaddr_ipv4->sin_addr);
if (Address != "0.0.0.0") break;
}
freeaddrinfo(result);
}
if ((this->socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
{
this->Close();
throw std::runtime_error("Error: Failed to create socket");
}
struct sockaddr_in SockAddr;
memset(&SockAddr, 0, sizeof(SockAddr));
SockAddr.sin_port = htons(Port);
SockAddr.sin_family = AF_INET;
SockAddr.sin_addr.s_addr = (Address == "INADDR_ANY" ? htonl(INADDR_ANY) : inet_addr(Address.c_str()));
if (Listen && (bind(this->socket, reinterpret_cast<SOCKADDR*>(&SockAddr), sizeof(SockAddr)) == SOCKET_ERROR))
{
this->Close();
throw std::runtime_error("Error: Socket binding failed");
}
if (Listen && (listen(this->socket, SOMAXCONN) == SOCKET_ERROR))
{
this->Close();
throw std::runtime_error("Error: Socket Listening Failed");
}
if(!Listen && (connect(this->socket, reinterpret_cast<SOCKADDR*>(&SockAddr), sizeof(SockAddr)) == SOCKET_ERROR))
{
if(Asynchronous && WSAGetLastError() != WSAEWOULDBLOCK)
{
this->Close();
throw std::runtime_error("Error: Socket Connection failed");
}
else if (!Asynchronous)
{
this->Close();
throw std::runtime_error("Error: Socket Connection failed");
}
}
}
}
SOCKET Socket::Accept(sockaddr* ClientInfo, int* ClientInfoSize)
{
static int Size = sizeof(sockaddr);
return accept(this->socket, ClientInfo, (ClientInfo && ClientInfoSize ? ClientInfoSize : &Size));
}
Socket& Socket::operator = (Socket && S)
{
S.Swap(*this);
return *this;
}
int Socket::Recv(void* Buffer, std::uint32_t BufferLength)
{
return recv(this->socket, reinterpret_cast<char*>(Buffer), BufferLength, 0);
}
int Socket::Recv(SOCKET S, void* Buffer, std::uint32_t BufferLength)
{
return recv(S, reinterpret_cast<char*>(Buffer), BufferLength, 0);
}
std::uint32_t Socket::RecvEx(void* Buffer, std::uint32_t BufferLength)
{
return this->RecvEx(this->socket, Buffer, BufferLength);
}
std::uint32_t Socket::RecvEx(SOCKET S, void* Buffer, std::uint32_t BufferLength)
{
UnInitialized();
char* Pointer = reinterpret_cast<char*>(Buffer);
std::uint32_t TotalRead = 0;
while (BufferLength > 0)
{
int BytesRead = recv(S, Pointer, std::min(1024 * 1024, static_cast<int>(BufferLength)), 0);
if (BytesRead < 0)
{
if ((BytesRead == SOCKET_ERROR) && (WSAGetLastError() == WSAEWOULDBLOCK))
continue;
throw std::runtime_error("Error! RecvEx: Failed To Read Bytes.");
}
if (BytesRead == 0) break;
Pointer += BytesRead;
BufferLength -= BytesRead;
TotalRead += BytesRead;
}
return TotalRead;
}
int Socket::Send(void* Buffer, std::size_t BufferSize)
{
return send(this->socket, reinterpret_cast<char*>(Buffer), BufferSize, 0);
}
int Socket::Send(SOCKET S, void* Buffer, std::size_t BufferSize)
{
return send(S, reinterpret_cast<char*>(Buffer), BufferSize, 0);
}
void Socket::Swap(Socket &S)
{
using std::swap;
swap(socket, S.socket);
swap(Port, S.Port);
swap(Address, S.Address);
swap(Listen, S.Listen);
swap(Initialized, S.Initialized);
swap(Asynchronous, S.Asynchronous);
}
void Socket::UnInitialized()
{
if (!Initialized)
{
throw std::runtime_error("\nError! Socket Not Constructed!");
std::cout << "Socket Not Constructed!\n";
ExitProcess(0);
}
}
Server.cpp:
#include "Sockets.hpp"
#define PORT 27015
#define ADDRESS INADDR_ANY
#define CLIENTCOUNT 2
typedef struct
{
std::string ip;
int port;
SOCKET sock;
} ClientInfo;
template <typename T>
inline T ReadPointer(TCHAR* &Pointer)
{
T Result = *(reinterpret_cast<T*>(Pointer));
Pointer += sizeof(T) / sizeof(TCHAR);
return Result;
}
template <typename T>
inline void WritePointer(TCHAR* &Pointer, const T& Value)
{
*(reinterpret_cast<T*>(Pointer)) = Value;
Pointer += sizeof(T) / sizeof(TCHAR);
}
bool SendClient(ClientInfo* client, ClientInfo* receiver)
{
int datasize = sizeof(client->ip.size()) + client->ip.size() + sizeof(client->port);
std::vector<char> buffer(datasize, 0);
char* ptr = &buffer[0];
WritePointer(ptr, client->ip.size());
for (std::size_t i = 0; i < client->ip.size(); ++i)
WritePointer(ptr, client->ip[i]);
WritePointer(ptr, client->port);
std::cout << "Sending: " << &buffer[0] << "\n";
return send(receiver->sock, &buffer[0], datasize, 0) == datasize;
}
bool ReadClient(SOCKET sock, ClientInfo* client)
{
std::size_t ip_size = 0;
recv(sock, (char*) &ip_size, sizeof(client->ip.size()), 0);
client->ip.resize(ip_size);
recv(sock, &client->ip[0], ip_size, 0);
recv(sock, (char*) &client->port, sizeof(int), 0);
std::cout<<client->ip<<"\n";
return true;
}
int main()
{
Socket s;
s.Connect(PORT, "localhost", true, false);
char buffer[1024] = {0};
std::vector<ClientInfo> clients;
while(true)
{
if (clients.size() < CLIENTCOUNT)
{
sockaddr_in ClientAddressInfo = {0};
SOCKET sock = s.Accept(reinterpret_cast<sockaddr*>(&ClientAddressInfo), nullptr);
char* ip = inet_ntoa(ClientAddressInfo.sin_addr);
int port = (int) ntohs(ClientAddressInfo.sin_port);
ClientInfo info = {ip, port, sock};
clients.push_back(info);
std::cout << "Client Connected From: " << ip << " on port: " << port << "\n";
}
if (ReadAsync(s, buffer))
{
std::cout << "Connected\n";
}
std::this_thread::sleep_for(std::chrono::milliseconds(100));
if (clients.size() >= CLIENTCOUNT)
{
SendClient(&clients[0], &clients[1]);
SendClient(&clients[1], &clients[0]);
return 0;
}
}
}
Client.cpp:
#define PORT 27015
#define ADDRESS INADDR_ANY
#define CLIENTCOUNT 2
typedef struct
{
std::string ip;
int port;
SOCKET sock;
} ClientInfo;
template <typename T>
inline T ReadPointer(TCHAR* &Pointer)
{
T Result = *(reinterpret_cast<T*>(Pointer));
Pointer += sizeof(T) / sizeof(TCHAR);
return Result;
}
template <typename T>
inline void WritePointer(TCHAR* &Pointer, const T& Value)
{
*(reinterpret_cast<T*>(Pointer)) = Value;
Pointer += sizeof(T) / sizeof(TCHAR);
}
bool SendClient(ClientInfo* client, ClientInfo* receiver)
{
int datasize = sizeof(client->ip.size()) + client->ip.size() + sizeof(client->port);
std::vector<char> buffer(datasize, 0);
char* ptr = &buffer[0];
WritePointer(ptr, client->ip.size());
for (std::size_t i = 0; i < client->ip.size(); ++i)
WritePointer(ptr, client->ip[i]);
WritePointer(ptr, client->port);
std::cout << "Sending: " << &buffer[0] << "\n";
return send(receiver->sock, &buffer[0], datasize, 0) == datasize;
}
bool ReadClient(SOCKET sock, ClientInfo* client)
{
std::size_t ip_size = 0;
recv(sock, (char*) &ip_size, sizeof(client->ip.size()), 0);
client->ip.resize(ip_size);
recv(sock, &client->ip[0], ip_size, 0);
recv(sock, (char*) &client->port, sizeof(int), 0);
return true;
}
bool ReadAsync(const Socket &sock, ClientInfo* client)
{
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 100000;
fd_set rfds;
FD_ZERO(&rfds);
FD_SET(sock.GetSocket(), &rfds);
for (int i = 0; i < 600; ++i)
{
if (select(sock.GetSocket(), &rfds, &rfds, NULL, &tv))
{
return ReadClient(sock.GetSocket(), client);
}
tv.tv_sec = 0;
tv.tv_usec = 100000;
}
return false;
}
int main()
{
Socket s;
s.Connect(PORT, "localhost", false, false);
std::vector<SOCKET> clients;
ClientInfo client = {};
while(true)
{
if (ReadAsync(s, &client))
{
std::cout<<"IP: "<<client.ip<<" PORT: "<<client.port<<"\n";
s = std::move(Socket(client.port, client.ip, true, false));
}
std::this_thread::sleep_for(std::chrono::milliseconds(100));
system("CLS");
std::cout<<"Connecting..\n";
}
}