I am recently working on a project based on usrsctp.
When creating a new SCTP socket, one can specify a callback function which will be called when new data is available as shown in the code below.
create a new SCTP socket:
struct socket *s = usrsctp_socket(AF_CONN, SOCK_STREAM, IPPROTO_SCTP,
sctp_data_received_cb, NULL, 0, sctp);
callback function:
static int
sctp_data_received_cb(struct socket *sock, union sctp_sockstore addr, void *data,
size_t len, struct sctp_rcvinfo recv_info, int flags, void *user_data)
{
struct sctp_transport *sctp = (struct sctp_transport *)user_data;
if (sctp == NULL || len == 0)
return -1;
fprintf(stdout, "Data of length %u received on stream %u with SSN %u, TSN %u, PPID %u\n",
(uint32_t)len,
recv_info.rcv_sid,
recv_info.rcv_ssn,
recv_info.rcv_tsn,
ntohl(recv_info.rcv_ppid));
if (flags & MSG_NOTIFICATION)
handle_notification_message(sctp, (union sctp_notification *)data, len);
else
handle_rtcdc_message(sctp, data, len, ntohl(recv_info.rcv_ppid), recv_info.rcv_sid);
free(data);
return 0;
}
This callback function is called properly, but its parameter values are just nonsense. Output of the code above is like
Data of length 675381504 received on stream 31504 with SSN 34835, TSN 32651, PPID 8470824
which should have been like
Data of length 18 received on stream 0 with SSN 0, TSN 4117987333, PPID 50
I read the source code of usrsctp and found where the callback is called:
if (control->spec_flags & M_NOTIFICATION) {
flags |= MSG_NOTIFICATION;
}
inp->recv_callback(so, addr, buffer, control->length, rcv, flags, inp->ulp_info);
SCTP_TCB_LOCK(stcb);
Change it to the code below and recompile the library
if (control->spec_flags & M_NOTIFICATION) {
flags |= MSG_NOTIFICATION;
}
fprintf(stdout, "[LIB] Data of length %u received on stream %u with SSN %u, TSN %u, PPID %u\n",
control->length,
rcv.rcv_sid,
rcv.rcv_ssn,
rcv.rcv_tsn,
ntohl(rcv.rcv_ppid));
inp->recv_callback(so, addr, buffer, control->length, rcv, flags, inp->ulp_info);
SCTP_TCB_LOCK(stcb);
I can get expected output:
[LIB] Data of length 18 received on stream 0 with SSN 0, TSN 4117987333, PPID 50
Why did parameter values become nonsense in the callback function?
I have found a similar question here, but couldn't understand its answer. I am quite sure it is the same issue.
[update1]
the prototype of usrsctp_socket in usrsctp.h:
struct socket *
usrsctp_socket(int domain, int type, int protocol,
int (*receive_cb)(struct socket *sock, union sctp_sockstore addr, void *data,
size_t datalen, struct sctp_rcvinfo, int flags, void *ulp_info),
int (*send_cb)(struct socket *sock, uint32_t sb_free),
uint32_t sb_threshold,
void *ulp_info);
[update2]
I am quite sure that no extra tricks as suggested in the old similar thread are needed, since I see no weird castings in the official examples and they just work well.
for example in echo_server.c:
static int
receive_cb(struct socket *sock, union sctp_sockstore addr, void *data,
size_t datalen, struct sctp_rcvinfo rcv, int flags, void *ulp_info)
{
char namebuf[INET6_ADDRSTRLEN];
const char *name;
uint16_t port;
if (data) {
if (flags & MSG_NOTIFICATION) {
printf("Notification of length %d received.\n", (int)datalen);
} else {
switch (addr.sa.sa_family) {
#ifdef INET
case AF_INET:
name = inet_ntop(AF_INET, &addr.sin.sin_addr, namebuf, INET_ADDRSTRLEN);
port = ntohs(addr.sin.sin_port);
break;
#endif
#ifdef INET6
case AF_INET6:
name = inet_ntop(AF_INET6, &addr.sin6.sin6_addr, namebuf, INET6_ADDRSTRLEN),
port = ntohs(addr.sin6.sin6_port);
break;
#endif
case AF_CONN:
#ifdef _WIN32
_snprintf(namebuf, INET6_ADDRSTRLEN, "%p", addr.sconn.sconn_addr);
#else
snprintf(namebuf, INET6_ADDRSTRLEN, "%p", addr.sconn.sconn_addr);
#endif
name = namebuf;
port = ntohs(addr.sconn.sconn_port);
break;
default:
name = NULL;
port = 0;
break;
}
printf("Msg of length %d received from %s:%u on stream %d with SSN %u and TSN %u, PPID %d, context %u.\n",
(int)datalen,
name,
port,
rcv.rcv_sid,
rcv.rcv_ssn,
rcv.rcv_tsn,
ntohl(rcv.rcv_ppid),
rcv.rcv_context);
if (flags & MSG_EOR) {
struct sctp_sndinfo snd_info;
snd_info.snd_sid = rcv.rcv_sid;
snd_info.snd_flags = 0;
if (rcv.rcv_flags & SCTP_UNORDERED) {
snd_info.snd_flags |= SCTP_UNORDERED;
}
snd_info.snd_ppid = rcv.rcv_ppid;
snd_info.snd_context = 0;
snd_info.snd_assoc_id = rcv.rcv_assoc_id;
if (usrsctp_sendv(sock, data, datalen, NULL, 0, &snd_info, sizeof(struct sctp_sndinfo), SCTP_SENDV_SNDINFO, 0) < 0) {
perror("sctp_sendv");
}
}
}
free(data);
}
return (1);
}
OK, I figured out why myself. It is silly but I will post the solution here in case someone would need it.
The defination of union sctp_sockstore (type of the second parameter of the callback function) is shown below.
union sctp_sockstore {
#if defined(INET)
struct sockaddr_in sin;
#endif
#if defined(INET6)
struct sockaddr_in6 sin6;
#endif
struct sockaddr_conn sconn;
struct sockaddr sa;
};
INET and INET6 are defined in usrsctp library but not in my code, since I handcrafted the Makefile and omitted them. The parameters were shifted (like 16bit) because of different sizes of the unions and so became nonsense.
Defining INET and INET6 (especially INET6) when you compile your own code solves the problem.
Related
I'm trying to intercept winsock2 calls to troubleshoot a case where UDP packets between processes on the same host intermittently vanish. When they "vanish" they vanish for something like 20 seconds, which is enough to abort the process being run.
I managed to get the DLL injection to work, and 2 winsock calls are intercepted correctly (I hope) because I can do a simple print, but I need to be able to process the address information so I can track who sends what to whom...
Unfortunately, the upstream process I'm injecting into is apparently calling recvfrom (Yes, not the WSA... equivalent, this is old ported POSIX code) with NULL's for the "from" and "fromlen" parameters. If I don't fiddle with them at all the receive works. If I do the below, I get "Invalid Address" errors (Winsock error 10014).
An I doing something stupid here? Not that I would be surprised.... And yes, it would be easier to rebuild the target application with the desired debugging, but the build environment is down due to a data center migration, and I need ammunition to say "it's not the application."
// dllmain.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include "mhook.h"
#include <winsock2.h>
// typedefs for function pointers...
typedef int(WINAPI *rcvfrom_ptr) (
SOCKET s,
char *buf,
int len,
int flags,
struct sockaddr *from,
int *fromlen
);
typedef int(WINAPI *sendto_ptr) (
_In_ SOCKET s,
_In_ const char *buf,
_In_ int len,
_In_ int flags,
_In_ const struct sockaddr *to,
_In_ int tolen
);
// Function pointers for original calls.
rcvfrom_ptr orig_rcvfrom;
sendto_ptr orig_sendto;
//
// Helper functions.
//
typedef union sockaddrs {
struct sockaddr from;
struct sockaddr_in in_from;
// Need to verify Ipv6 support. may need to remigrate back to VS 2015
//struct sockaddr_in6 in6_from;
} tsockaddrs;
char *printaddr(char *buff,const int buffsz, const tsockaddrs *addr)
{
...
}
// Shim functions.
//
// Still working on getting them to actually work and do what I need.
// But I may as well develop the skeleton
int WINAPI Myrecvfrom(SOCKET s,
char *buf,
int len,
int flags,
struct sockaddr *from,
int *fromlen
)
{
int result;
struct sockaddr *all_froms;
char addrbuff[100] = "";
int newfromlen = sizeof(struct sockaddr);
all_froms = (struct sockaddr *)malloc(sizeof(struct sockaddr));
memset((void *)all_froms,0,sizeof(struct sockaddr));
printf("Receiving Packet!\n");
if (from == NULL) {
printf("\tFrom addr == null, using internal structures\n");
result = (orig_rcvfrom)(s, buf, len, flags, all_froms, &newfromlen);
} else {
printf("\tFrom addr != null, using passed structures\n");
result = (orig_rcvfrom)(s, buf, len, flags, from, fromlen);
memcpy_s((void*)&all_froms,sizeof(all_froms),(void *)from,*fromlen);
if (fromlen != NULL) {
newfromlen=*fromlen;
} else {
newfromlen=sizeof(struct sockaddr);
}
}
if (result >0) {printf("received %d bytes\n",result);}
else if (result == SOCKET_ERROR) {printf("Socket Error %d occurred!\n",WSAGetLastError());}
if (newfromlen >0) {
if (printaddr(addrbuff,sizeof(addrbuff),(tsockaddrs *)all_froms)!=NULL) {
printf("received %d bytes from on port %d from host %s\n",result,((tsockaddrs *)(all_froms))->in_from.sin_port,addrbuff);
}
if (from != NULL) {
memcpy_s((void*)from,sizeof(struct sockaddr),(void*)&all_froms,newfromlen);
}
else
{
}
if (fromlen != NULL) *fromlen=newfromlen;
}
else {
printf("received %d bytes from unknown port and host\n",result);
}
if (all_froms != NULL) {free(all_froms);}
return result;
}
int WINAPI Mysendto(SOCKET s,
const char *buf,
int len,
int flags,
const struct sockaddr *to,
int tolen
)
{
printf("Sending packet!\n");
return orig_sendto(s, buf, len, flags, to, tolen);
}
BOOL AttachHooks(void)
{
BOOL sethooks;
orig_rcvfrom = (rcvfrom_ptr)GetProcAddress(GetModuleHandle(L"ws2_32"), "recvfrom");
sethooks = Mhook_SetHook((PVOID*)&orig_rcvfrom, Myrecvfrom);
if (sethooks) {
orig_sendto = (sendto_ptr)GetProcAddress(GetModuleHandle(L"ws2_32"), "sendto");
sethooks &= Mhook_SetHook((PVOID*)&orig_sendto, Mysendto);
}
return sethooks;
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
printf_s("This is an attached DLL!\n");
AttachHooks();
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
The cause of the issue is that the ACTUAL size of the reply was more than the size of "struct sockaddr." It in fact was a SOCKADDR_IN6 structure coming back. Used an arbitrary buffer of 200 bytes instead of the 28-byte sockaddr structure and I was able to pull in the data.
In the process, I wound up converting to "peeking" the received data instead of processing it after it was pulled in. When the PC with the source code finishes installing updates, I'll post it.
Working from home is fairly isolating, and there isn't anyone who lives in winsock in my office anyway. It was really helpful to "chat" in the comments.
How can I get the interface name for the IP address in linux from C code ?
e.g. I'd like to get the interface name ( like etho , eth1 , l0 ) assigned for the IP address 192.168.0.1
Using /proc/net/arp you can match it. Here is a command line tool example.
usage: getdevicebyip 192.168.0.1
#include <stdio.h>
#include <fcntl.h>
int main(int argc, char **argv){
if (argc < 2) return 1;
FILE *fp = fopen("/proc/net/arp", "r");
char ip[99], hw[99], flags[99], mac[99], mask[99], dev[99], dummy[99];
fgets(dummy, 99, fp); //header line
while (fscanf(fp, "%s %s %s %s %s %s\n", ip, hw, flags, mac, mask, dev) != EOF)
if (!strcmp(argv[1],ip))
printf("%s\n",dev);
return 0;
}
You can use getifaddrs. See man 3 getifaddrs for usage information. This will only work on a Unix-like systems.
netlink is a way to do this on Linux. I think it might even be a proper way to do it on Linux (even though it isn't portable).
The strategy is:
Get a list of addresses on interfaces from the kernel by sending a netlink message.
Find the address you want (I have hard coded the one I want as address_dq) and record its interface (a number at this stage)
Get a list of interfaces by sending another netlink message,
Find the number of the interface matching the number you recorded in step (2).
Get the name of the interface.
The code below is not pretty, but I'm sure you could do a better job of it. I have been a especially sloppy by not checking for a multipart message (checking for the NLM_F_MULTI flag and for a message type of NLMSG_DONE is the way to do it). Instead I have just assumed the response to the first message is multipart -- it is on my machine -- and chewed up the NLMSG_DONE message which follows.
Code...
#include <asm/types.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <sys/socket.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, void ** argv) {
// This is the address we want the interface name for,
// expressed in dotted-quad format
char * address_dq = "127.0.0.1";
// Convert it to decimal format
unsigned int address;
inet_pton(AF_INET, address_dq, &address);
char buf[16384];
// Our first message will be a header followed by an address payload
struct {
struct nlmsghdr nlhdr;
struct ifaddrmsg addrmsg;
} msg;
// Our second message will be a header followed by a link payload
struct {
struct nlmsghdr nlhdr;
struct ifinfomsg infomsg;
} msg2;
struct nlmsghdr *retmsg;
// Set up the netlink socket
int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
// Fill in the message
// NLM_F_REQUEST means we are asking the kernel for data
// NLM_F_ROOT means provide all the addresses
// RTM_GETADDR means we want address information
// AF_INET means limit the response to ipv4 addresses
memset(&msg, 0, sizeof(msg));
msg.nlhdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
msg.nlhdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
msg.nlhdr.nlmsg_type = RTM_GETADDR;
msg.addrmsg.ifa_family = AF_INET;
// As above, but RTM_GETLINK means we want link information
memset(&msg2, 0, sizeof(msg2));
msg2.nlhdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
msg2.nlhdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
msg2.nlhdr.nlmsg_type = RTM_GETLINK;
msg2.infomsg.ifi_family = AF_UNSPEC;
// Send the first netlink message
send(sock, &msg, msg.nlhdr.nlmsg_len, 0);
int len;
// Get the netlink reply
len = recv(sock, buf, sizeof(buf), 0);
retmsg = (struct nlmsghdr *)buf;
// Loop through the reply messages (one for each address)
// Each message has a ifaddrmsg structure in it, which
// contains the prefix length as a member. The ifaddrmsg
// structure is followed by one or more rtattr structures,
// some of which (should) contain raw addresses.
while NLMSG_OK(retmsg, len) {
struct ifaddrmsg *retaddr;
retaddr = (struct ifaddrmsg *)NLMSG_DATA(retmsg);
int iface_idx = retaddr->ifa_index;
struct rtattr *retrta;
retrta = (struct rtattr *)IFA_RTA(retaddr);
int attlen;
attlen = IFA_PAYLOAD(retmsg);
char pradd[128];
// Loop through the routing information to look for the
// raw address.
while RTA_OK(retrta, attlen) {
if (retrta->rta_type == IFA_ADDRESS) {
// Found one -- is it the one we want?
unsigned int * tmp = RTA_DATA(retrta);
if (address == *tmp) {
// Yes!
inet_ntop(AF_INET, RTA_DATA(retrta), pradd, sizeof(pradd));
printf("Address %s ", pradd);
// Now we need to get the interface information
// First eat up the "DONE" message waiting for us
len = recv(sock, buf, sizeof(buf), 0);
// Send the second netlink message and get the reply
send(sock, &msg2, msg2.nlhdr.nlmsg_len, 0);
len = recv(sock, buf, sizeof(buf), 0);
retmsg = (struct nlmsghdr *)buf;
while NLMSG_OK(retmsg, len) {
struct ifinfomsg *retinfo;
retinfo = NLMSG_DATA(retmsg);
if (retinfo->ifi_index == iface_idx) {
retrta = IFLA_RTA(retinfo);
attlen = IFLA_PAYLOAD(retmsg);
char prname[128];
// Loop through the routing information
// to look for the interface name.
while RTA_OK(retrta, attlen) {
if (retrta->rta_type == IFLA_IFNAME) {
strcpy(prname, RTA_DATA(retrta));
printf("on %s\n", prname);
exit(EXIT_SUCCESS);
}
retrta = RTA_NEXT(retrta, attlen);
}
}
retmsg = NLMSG_NEXT(retmsg, len);
}
}
}
retrta = RTA_NEXT(retrta, attlen);
}
retmsg = NLMSG_NEXT(retmsg, len);
}
}
When run as above, returns Address 127.0.0.1 on lo.
Using "192.168.1.x" instead of "127.0.0.1" it instead returns Address 192.168.1.x on eth0.
I am having some trouble with some functions that won't compile properly. They are pretty much borrowed from an example program to get a better understanding of how network programming works and to see if I could put together a reliable TCP connection (3 way handshake) using RAW sockets. These are the functions:
void recieve(u_char *args, const struct pcap_pkthdr *pkthdr, const u_char *buffer)
{
const int one = 1;
u_char *ptr;
int LEN = args; /* FIRST WARNING POINTS HERE */
struct ipheader *ip;
struct tcpheader *tcp;
ip = (struct ipheader *)(buffer + LEN);
tcp = (struct tcpheader *)(buffer + LEN + sizeof (struct ipheader));
printf("%d\n", LEN);
printf("Packet recieved. ACK number: %d\n", ntohl (tcp->tcph_seqnum));
printf("Packet recieved. SEQ number: %d\n", nthol (tcp->tcph_acknum));
s_seq = nthol (tcp->tcph_seqnum);
send_syn_ack(s_seq, dip, sip, dport, sport);
sleep(100);
}
and
void capture()
{
pcap_t *pd;
bpf_u_int32 netmask;
bpf_u_int32 localnet;
char *filter = ("ip dest host %s", dstip); /* SECOND WARNING POINTS HERE */
char *dev = NULL;
char errbuf[PCAP_ERRBUF_SIZE];
struct bpf_program filterprog;
int dl = 0, dl_len = 0;
if ((pd = pcap_open_live(dev, 1514, 1, 500, errbuf)) == NULL)
{
fprintf(stderr, "cannot open device %s: %s\n", dev, errbuf);
exit(1);
}
pcap_lookupnet(dev, &localnet, &netmask, errbuf);
pcap_compile(pd, &filterprog, filter, 0, localnet);
if (pcap_setfilter(pd, &filterprog) == - 1)
{
fprintf(stderr, "cannot set pcap filter %s: %s\n", filter, errbuf);
exit(1);
}
pcap_freecode(&filterprog);
dl = pcap_datalink(pd);
switch(dl) {
case 1:
dl_len = 14;
break;
default:
dl_len = 14;
break;
}
if (pcap_loop(pd, -1, recieve, (u_char *)dl_len) < 0) { /* LAST WARNING HERE */
fprintf(stderr, "cannot get raw packet: %s\n", pcap_geterr(pd));
exit(1);
}
}
and these are the error messages:
In function ‘recieve’:
warning: initialization makes integer from pointer without a cast
In function ‘capture’:
warning: initialization makes pointer from integer without a cast
Warning: cast to pointer from integer of different size
I get the first and last warning even in the example program. Are these two functions any good, and is there a simpler and cleaner way to achieve what they are meant to? if not, what should I do to get rid of these warnings? Thanks :)
u_char is a not a standard type. Equivalent is a uint8_t which is a part of C99 standard. More or less the first error please try,
int LEN = *args
uint8_t is defined in the library stdint.h
In the second error place, do the following,
`char *s = "ip dest host ";
char *filter = (char *)malloc(strlen(s) + strlen(dstip) + 1);
strcpy(filter,s);
strcat(filter,dstip);'
Please include for string functions strlen, strcpy and strcat.
Well, the warnings are correct - in recieve(), the first argument is u_char *args, and in the line you flag, you are attempting to assign args to int LEN; args isn't an int, and you're not explicitly asking for it to be converted to an int, so the compiler warns about it.
For the second one, I'm not sure what type dstip is, since the declaration/definition is not included in the code you posted, but if it's not a char *, that would explain the second message.
For the third one, I'd have to know what pcap_loop() is expecting in place of the u_char * you are passing it, but that's likely also a mismatch.
I am trying to get some message from kernel space to userspace, when a condition fails!
Here's my kernel code:
#define MESSAGTOUSER 1
int ret_val;
struct siginfo sinfo;
pid_t id;
struct task_struct *task;
unsigned char msgBuffer[20];
unsigned char buf1[20]= "HI";
static int major_no;
static struct class *safe_class;
static long device_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
static int device_open(struct inode *inode, struct file *file);
static int device_write(struct file *file, const char *gdata, size_t len, loff_t *off);
static int device_read(struct file *file, char *buf, size_t len, loff_t *off);
static int device_release(struct inode *inode, struct file *file);
int failureDetection (char* faultMsg) {
strcpy (msgBuffer, faultMsg);
printk(KERN_ALERT"\nMessage from HBM %s\n", msgBuffer);
printk(KERN_ALERT".......... RETURN VALUE ...... : %d", ret_val);
int Reg_Dev(void);
memset (&sinfo, 0, sizeof(struct siginfo));
sinfo.si_signo = SIGUSR1;
sinfo.si_code = SI_USER;
if (id == 0) {
printk("\ncan't find User PID: %d\n", id);
}else {
//task = pid_task(find_vpid(pid), PIDTYPE_PID);
task = find_task_by_vpid(id);
send_sig_info(SIGUSR1, &sinfo, task);
}
return 0;
}
static int device_open(struct inode *inode, struct file *file){
/*sucess*/
return 0;
}
void strPrint(void) {
printk("value of msgBuffer: %s", msgBuffer);
}
static int device_write(struct file *file, const char *gdata, size_t len, loff_t *off){
get_user (id,(int *)gdata);
if(id <0)
printk(KERN_ALERT"Cann't find PID from userspace its : %i", id);
else
printk(KERN_ALERT"Successfully received the PID of userspace %i", id);
return len;
}
static int
device_read(struct file *file, char *buf, size_t len, loff_t *off){
/*success*/
return 0;
}
static int device_release(struct inode *inode, struct file *file){
/*success*/
return 0;
}
static long device_ioctl(struct file *file, unsigned int cmd, unsigned long arg) {
switch (cmd) {
case MESSAGTOUSER:
ret_val = copy_to_user((char *)arg, msgBuffer, sizeof(arg));
printk("Msg of Kernel %s", msgBuffer);
break;
default:
break;
}
return 0;
}
static struct file_operations fops = {
.open = device_open,
.write = device_write,
.read = device_read,
.release = device_release,
.unlocked_ioctl = device_ioctl
};
int Reg_Dev(void) {
major_no = register_chrdev(0, "safe_dev", &fops);
safe_class = class_create(THIS_MODULE, "safe_dev");
device_create(safe_class,NULL, MKDEV(major_no, 0), "safe_dev");
printk("\n Device Registered and Created \n");
return 0;
}
void UnReg_dev (void) {
printk("\nUser PID : %d\n", id);
unregister_chrdev(major_no, "safe_dev");
device_destroy(safe_class, MKDEV(major_no,0));
class_unregister(safe_class);
class_destroy(safe_class);
printk("\n Device Un-Registered and Destroyed \n");
}
extern int Reg_Dev(void);
for he userspace i have this code:
#define PORT 9930
#define G_IP "192.168.10.71"
#define BUFLEN 512
#define MESSAGTOUSER 0
unsigned char *str[20];
char b1[BUFLEN], b2[BUFLEN];
struct sockaddr_in me,client;
int s, i, n=sizeof(me);
int fd;
void error_handler(char *s) {
perror(s);
exit(1);
}
void signal_handler (int signum) {
if(signum == SIGUSR1)
{
printf("\n%s\n",str);
if((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
error_handler("\nERROR: in Socket\n");
memset((char *) &me, 0, sizeof(me));
me.sin_family = AF_INET;
me.sin_port = PORT;
if (inet_aton(G_IP, &me.sin_addr)==0)
{
fprintf(stderr, "inet_aton() failed\n");
exit(1);
}
printf("Message from Kernel : %s", &str);
//strcpy (str, newStr);
int cntr =0; sprintf(b2, "\nFailure Message: %s\n",str);
printf("\nsending Fault to PMN Group : Tick - %d\n", cntr++);
if(sendto(s, str, sizeof(str),0,(struct sockaddr *) &me,n)==-1)
error_handler("\nERROR: in sendto()\n");
close (s);
// counter ++;
// sendAndReceiveOverUDP();
return;
}
}
int main() {
pid_t u_id;
u_id = getpid();
int i = 1;
fd = open("/dev/safe_dev",O_RDWR);
write(fd, &u_id, 4);
ioctl (fd, MESSAGTOUSER, &str);
printf("\n PID sent to device successfully: %d \n", u_id);
close(fd);
signal(SIGUSR1, signal_handler);
printf("\nMy PID is: %d\n",u_id);
//printf("Subnet 1 working fine.. Tick - %d", tv.tv_sec);
while (1)
sleep(1);
return 0;
}
Now what I am expecting to receive on Userspace:
Message from Kernel: A<->B
Sending Fault o PMN Group : tick - 0
Message from Kernel: B<->B
Sending Fault o PMN Group : tick - 1
....
...
but what is the output:
Message from Kernel:
Sending Fault o PMN Group : tick - 0
Message from Kernel:
Sending Fault o PMN Group : tick - 1
....
...
It seems that copy_to_user is not working, while in simple program just copying a string from kernel to user is working fine, but while i am using in this scenario then its not working, its compiling without any warning,
Some other Details:
failureDetection() is getting a string like A<->B mentioned in output from rest of the programs..
the same message from failureDetection is printing on kernel level but not transferring at the user level.
I have also tried to create an own string in this and tried to transfer that, but it is also not working! suppose msgBuffer = HI, then I should receive HI on to the userspace. but its not happening! can anyone please please make me correct whats wrong with this code? how can i get updates onto the userspace!!??
Sindhu..
The copy_to_user() only happens in response to the ioctl(), which only happens once, very early on in your code. Presumably at that point the kernel buffer msgBuffer is empty, because the failureDetection() function has not yet run at that point. It doesn't matter if failureDetection() runs later and sets msgBuffer then, because your userspace program never calls the ioctl() again so it doesn't see the new contents of msgBuffer.
You also have a bug in your copy_to_user() call - instead of sizeof(args) (which is a constant 4) you should probably use sizeof msgBuffer.
#caf: Thank you so much..
void signal_handler (int signum) {
if(signum == SIGUSR1)
{
fd = open ("/dev/safe_dev",O_RDWR);
ioctl (fd, MESSAGTOUSER, &str);
close (fd);
if((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
error_handler("\nERROR: in Socket\n");
memset((char *) &me, 0, sizeof(me));
me.sin_family = AF_INET;
me.sin_port = PORT;
if (inet_aton(G_IP, &me.sin_addr)==0)
{
fprintf(stderr, "inet_aton() failed\n");
exit(1);
}
printf("Failure Detected on Eth Cards as : %s are non reachable.", str);
printf("\nsending Fault to PMN Group : Tick - %d\n", cntr++);
sprintf(b2, "\nFailure Message: %s\n",str);
if(sendto(s, str, sizeof(str),0,(struct sockaddr *) &me,n)==-1)
error_handler("\nERROR: in sendto()\n");
close (s);
return;
}
}
I was just making a stupid mistake.. hehehe.. i was not adding it in between file open and close block.. your suggestion resolved my issue...
Thank you so much for your response..
Rahee..
I have this libnetfilter_queue application which receives packets from kernel based on some iptables rule. Before going straight to my problem, i'm giving a sample workable code and other tools to set up a test environment so that We problem definition and possible solutions can be more accurate and robust.
The following code describes the core functionality of the application:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <linux/types.h>
#include <linux/netfilter.h> /* for NF_ACCEPT */
#include <errno.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
#define PREROUTING 0
#define POSTROUTING 4
#define OUTPUT 3
/* returns packet id */
static u_int32_t
print_pkt (struct nfq_data *tb)
{
int id = 0;
struct nfqnl_msg_packet_hdr *ph;
struct nfqnl_msg_packet_hw *hwph;
u_int32_t mark, ifi;
int ret;
unsigned char *data;
ph = nfq_get_msg_packet_hdr (tb);
if (ph)
{
id = ntohl (ph->packet_id);
printf ("hw_protocol=0x%04x hook=%u id=%u ",
ntohs (ph->hw_protocol), ph->hook, id);
}
hwph = nfq_get_packet_hw (tb);
if (hwph)
{
int i, hlen = ntohs (hwph->hw_addrlen);
printf ("hw_src_addr=");
for (i = 0; i < hlen - 1; i++)
printf ("%02x:", hwph->hw_addr[i]);
printf ("%02x ", hwph->hw_addr[hlen - 1]);
}
mark = nfq_get_nfmark (tb);
if (mark)
printf ("mark=%u ", mark);
ifi = nfq_get_indev (tb);
if (ifi)
printf ("indev=%u ", ifi);
ifi = nfq_get_outdev (tb);
if (ifi)
printf ("outdev=%u ", ifi);
ifi = nfq_get_physindev (tb);
if (ifi)
printf ("physindev=%u ", ifi);
ifi = nfq_get_physoutdev (tb);
if (ifi)
printf ("physoutdev=%u ", ifi);
ret = nfq_get_payload (tb, &data);
if (ret >= 0)
printf ("payload_len=%d ", ret);
fputc ('\n', stdout);
return id;
}
static int
cb (struct nfq_q_handle *qh, struct nfgenmsg *nfmsg,
struct nfq_data *nfa, void *data)
{
uint32_t ip_src, ip_dst;
struct in_addr s_ip;
struct in_addr d_ip;
uint16_t src_port;
uint16_t dst_port;
int verdict;
int id;
int ret;
unsigned char *buffer;
struct nfqnl_msg_packet_hdr *ph = nfq_get_msg_packet_hdr (nfa);
if (ph)
{
id = ntohl (ph->packet_id);
printf ("received packet with id %d", id);
}
ret = nfq_get_payload (nfa, &buffer);
ip_src = *((uint32_t *) (buffer + 12));
ip_dst = *((uint32_t *) (buffer + 16));
src_port = *((uint16_t *) (buffer + 20));
dst_port = *((uint16_t *) (buffer + 22));
s_ip.s_addr = (uint32_t) ip_src;
d_ip.s_addr = (uint32_t) ip_dst;
*(buffer + 26) = 0x00;
*(buffer + 27) = 0x00;
printf ( "source IP %s", inet_ntoa (s_ip));
printf ( "destination IP %s", inet_ntoa (d_ip));
printf ( "source port %d", src_port);
printf ( "destination port %d", dst_port);
if (ret)
{
switch (ph->hook)
{
case PREROUTING:
printf ( "inbound packet");
//my_mangling_fun();
break;
case OUTPUT:
printf ( "outbound packet");
//my_mangling_fun();
break;
}
}
verdict = nfq_set_verdict (qh, id, NF_ACCEPT, ret, buffer);
if (verdict)
printf ( "verdict ok");
return verdict;
}
int
main (int argc, char **argv)
{
struct nfq_handle *h;
struct nfq_q_handle *qh;
struct nfnl_handle *nh;
int fd;
int rv;
char buf[4096] __attribute__ ((aligned));
printf ("opening library handle\n");
h = nfq_open ();
if (!h)
{
fprintf (stderr, "error during nfq_open()\n");
exit (1);
}
printf ("unbinding existing nf_queue handler for AF_INET (if any)\n");
if (nfq_unbind_pf (h, AF_INET) < 0)
{
fprintf (stderr, "error during nfq_unbind_pf()\n");
exit (1);
}
printf ("binding nfnetlink_queue as nf_queue handler for AF_INET\n");
if (nfq_bind_pf (h, AF_INET) < 0)
{
fprintf (stderr, "error during nfq_bind_pf()\n");
exit (1);
}
printf ("binding this socket to queue '0'\n");
qh = nfq_create_queue (h, 0, &cb, NULL);
if (!qh)
{
fprintf (stderr, "error during nfq_create_queue()\n");
exit (1);
}
printf ("setting copy_packet mode\n");
if (nfq_set_mode (qh, NFQNL_COPY_PACKET, 0xffff) < 0)
{
fprintf (stderr, "can't set packet_copy mode\n");
exit (1);
}
fd = nfq_fd (h);
for (;;)
{
if ((rv = recv (fd, buf, sizeof (buf), 0)) >= 0)
{
printf ("pkt received\n");
nfq_handle_packet (h, buf, rv);
continue;
}
/* if your application is too slow to digest the packets that
* are sent from kernel-space, the socket buffer that we use
* to enqueue packets may fill up returning ENOBUFS. Depending
* on your application, this error may be ignored. Please, see
* the doxygen documentation of this library on how to improve
* this situation.
*/
if (rv < 0 && errno == ENOBUFS)
{
printf ("losing packets!\n");
continue;
}
perror ("recv failed");
break;
}
printf ("unbinding from queue 0\n");
nfq_destroy_queue (qh);
#ifdef INSANE
/* normally, applications SHOULD NOT issue this command, since
* it detaches other programs/sockets from AF_INET, too ! */
printf ("unbinding from AF_INET\n");
nfq_unbind_pf (h, AF_INET);
#endif
printf ("closing library handle\n");
nfq_close (h);
exit (0);
}
Notice in the callback function two calls to my_mangling_fun() is commented out. This is where i mangle the incoming and outgoing packet. I think this code would be sufficient to describe my case. If further clarification is need please ask, i will post further details.
Lets say accompanying iptables rules are following :
$iptables -t mangle -A PREROUTING -p udp --dport 5000 -j NFQUEUE
$iptables -t mangle -A OUTPUT -p udp --sport 5000 -j NFQUEUE
lets compile and fire udp the thing.
$gcc -g3 nfq_test.c -lnfnetlink -lnetfilter_queue
$./a.out (should be as root)
now we can feed garbage udp payload to this thing by netcat both client and server mode
$nc -ul 5000
$nc -uvv <IP> 5000
This will print the packet from my netfilter_queue app in stdout. Now that the development environment is set up, we can move to the next thing.
What we are trying to achieve is following :
Our server is listening on 5000 port. Now all incoming packet destined to udp port 5000 will be queued by kernel. And the handle to this queue will be given to user application we listed earlier. This queue mechanism works like this: When a packet is available, the callback function(cb() in our code) is called. after processing, the callback function calls nfq_set_verdict(). after a verdict is returned, next packet will pop from the queue. notice that a packet will not pop from queue if its preceding packet has not been issued a verdict. This verdict values are NF_ACCEPT for accepting packet, NF_DROP for dropping the packet.
Now what if i want to concatenate the udp payloads of the incoming and outgoing packet without touching client and server side code?
If i want to concatenate udp payloads from our app this very app, then we need to have multiple packets at hand. But we have seen that a packet does not pops from queue before a verdict is issued to its preceding one.
So how can this be done?
One possible solution is issue a NF_DROP to every packet and save those packets in an intermediate data structure. Let's say we have done it. But how can this packet can be delivered to the service listening on 5000 port?
We can't use network stack for delivering the packet, because if we do, then packets will end up in NFQUEUE again.
Another problem is, the server is totally agnostic about this app. That means it should not see any difference in the packets. It should see packets as if it came from the original client.
I have heard that a application can send data to a server in the same host without using network layer(ip,port) by writing some files. I do not know the validity of this statement. But if anyone knows anything about it , it will be wonderful.
I may get down voted for too much verbosity. But I think this can be fun session. we can find the solution together :)
I propose the following solution:
store packets in the application and return verdict NF_DROP
re-inject packets into the network stack using RAW sockets
tag concatenated UDP packets with a DSCP (see IP packet format)
in iptables, add a rule to match on this DSCP (--dscp) and ACCEPT the packet directly, without it passing through your netfilter application
If your provider already tags some packets with DSCP, you can add some iptables rules to clear them, like:
iptables -t mangle -A INPUT -j DSCP --set-dscp 0
I hope this solves your use-case.
First of all, thank you very much Aftnix! Your example kick started my automatic packet-inspecting wake-on-lan project. I want to my home server to sleep when it's idle, but wake up as soon as some requests come in. The idea is to inspect the request on a ddwrt router, decide it is a legit request and send a wol package. For SMTP the idea is to queue multiple packets, keep the other end happy with some bogus responses and kick in the real server transparantly.
I modified your example a little bit to queue up 1 packet and send it with the next packet. This is just a proof-of-concept, but it works fine.
// struct and variable needed to store 1 packet
struct packetbuffer {
struct nfq_q_handle *qh;
u_int32_t id;
u_int32_t verdict;
u_int32_t data_len;
unsigned char *buf;
};
struct packetbuffer pbuf;
int counter = 0;
static int cb (struct nfq_q_handle *qh, struct nfgenmsg *nfmsg,
struct nfq_data *nfa, void *data)
{
uint32_t ip_src, ip_dst;
struct in_addr s_ip;
struct in_addr d_ip;
uint16_t src_port;
uint16_t dst_port;
int verdict;
int id;
int ret;
unsigned char *buffer;
struct nfqnl_msg_packet_hdr *ph = nfq_get_msg_packet_hdr (nfa);
if (ph)
{
id = ntohl (ph->packet_id);
printf ("received packet with id %d", id);
}
ret = nfq_get_payload (nfa, &buffer);
ip_src = *((uint32_t *) (buffer + 12));
ip_dst = *((uint32_t *) (buffer + 16));
src_port = *((uint16_t *) (buffer + 20));
dst_port = *((uint16_t *) (buffer + 22));
s_ip.s_addr = (uint32_t) ip_src;
d_ip.s_addr = (uint32_t) ip_dst;
*(buffer + 26) = 0x00;
*(buffer + 27) = 0x00;
printf ( "source IP %s", inet_ntoa (s_ip));
printf ( "destination IP %s", inet_ntoa (d_ip));
printf ( "source port %d", src_port);
printf ( "destination port %d", dst_port);
if (ret)
{
switch (ph->hook)
{
case PREROUTING:
printf ( "inbound packet");
//my_mangling_fun();
break;
case OUTPUT:
printf ( "outbound packet");
//my_mangling_fun();
break;
}
}
// My modification starts here
if ((counter % 2) == 0)
{
pbuf.qh = qh;
pbuf.id = id;
pbuf.data_len = ret;
pbuf.buf = malloc(ret);
memcpy(pbuf.buf, buffer, ret);
printf(" queue package %d \n", id);
}
else
{
printf(" output 1st package %d, len=%d\n", pbuf.id, pbuf.data_len);
verdict = nfq_set_verdict (pbuf.qh, pbuf.id, NF_ACCEPT, pbuf.data_len, pbuf.buf);
free(pbuf.buf);
printf(" output 2nd package %d, len=%d\n", id, ret);
verdict = nfq_set_verdict (qh, id, NF_ACCEPT, ret, buffer);
}
counter++;
return 0;
}
This is not all code, but it should be pretty obvious what changed.
I know I'm a bit late to the party, but I decided to post this solution for future reference and hopefully some critics.
edit: hmm maybe I'd better write an userspace process like rinetd.