Linked List in C and getifaddrs() - c++

I've a problem with linked list. I'm using getifaddrs() to get ifaces info in Linux.
At first, i created an struct for save the interfaces infos.
This is a struct:
typedef struct iface {
char * interface_name;
char * interface_addr_ipv4;
char * interface_addr_ipv6;
char * interface_netmask;
char * interface_broadcast;
char * interface_mac_addr;
int interface_active;
struct iface * next_interface;
} Interface;
After this, i identify all ifaces of system in this way, even if they are not configured with an IP:
if (getifaddrs(&ifaddr) == -1)
return GET_INFO_IFACES_FAILED;
struct iface * iface_aux;
struct ifaddrs * ifaddr_aux;
struct sockaddr_in * ip;
iface_aux = iface;
for (ifaddr_aux=ifaddr;ifaddr_aux!=NULL;ifaddr_aux=ifaddr_aux->ifa_next) {
iface_aux->interface_name = ifaddr_aux->ifa_name;
if (ip->sin_family == AF_PACKET) {
get_interface_mac_addr(iface_aux);
iface_aux->interface_addr_ipv4 = NULL;
iface_aux->interface_addr_ipv6 = NULL;
iface_aux->next_interface = (Interface *) malloc(sizeof (Interface));
iface_aux = iface_aux->next_interface;
iface_aux->next_interface = NULL;
}
}
After all this, i do other loop to get ip address of interfaces, this is the code:
iface_aux = iface; //go to the firts pointer
for (ifaddr_aux=ifaddr;ifaddr_aux!=NULL;ifaddr_aux=ifaddr_aux->ifa_next) {
ip = (struct sockaddr_in *) ifaddr_aux->ifa_addr;
if (ip->sin_family == AF_INET) {
get_interface_ifaddr(iface_aux, ip);
get_interface_netmask(iface_aux, ifaddr);
get_interface_broadcast(iface_aux, ifaddr);
iface_aux = iface_aux->next_interface;
}
}
The code of function get_interface_ifaddr is:
int get_interface_ifaddr(Interface * iface, struct sockaddr_in * ip) {
iface->interface_addr_ipv4 = inet_ntoa(ip->sin_addr);
if (iface->interface_addr_ipv4 == NULL)
return GET_IFADDR_FAILED;
return GET_IPADDR_SUCCESS;
}
The problem is, when i do another loop to see the interfaces infos, all nodes of the list, stay with the last ip:
for (iface_aux=iface;iface_aux->next_interface!=NULL;iface_aux=iface_aux->next_interface) {
printf("Interface Name: %s\n", iface_aux->interface_name);
printf("Interface IP: %s\n", iface_aux->interface_addr_ipv4);
}
The strange thing is that the name of the interfaces is correct, but when i get the address, all nodes of the list, are to the same address.
Someone know what is going on?
PS: i'm new in c and linked list.
Thanks for your atention.

inet_ntoa uses a same memory region to return result. You need to allocate interface_addr_ipv4 by yourself and to copy the data manually.
char *tmp = inet_ntoa(ip->sin_addr);
iface->interface_addr_ipv4 = malloc(sizeof(char) * (strlen(tmp) + 1)); /* Don't forget to free() */
strcpy(iface->interface_addr_ipv4, tmp);
From the docs:
inet_ntoa() returns the dots-and-numbers string in a static buffer that is overwritten with each call to the function.
Better way is just to use inet_ntop:
inet_ntop(AF_INET, ip->sin_addr,
iface->interface_addr_ipv4, sizeof(iface->interface_addr_ipv4));
Where iface->interface_addr_ipv4 is an char array:
char interface_addr_ipv4[INET_ADDRSTRLEN];

Related

How to use libaudit?

I am trying to understand how to work with libaudit.
I want to recieve events about user actions using C/C++.
I don't understand how to set rules, and how to get information about user actions.
For example, I want to get information when user created directory.
int audit_fd = audit_open();
struct audit_rule_data *rule = (struct audit_rule_data *) malloc(sizeof(struct audit_rule_data));
memset(rule, 0, sizeof(struct audit_rule_data));
audit_rule_syscallbyname_data(rule, "mkdir");
audit_add_watch_dir(AUDIT_DIR, &rule, "/tmp");
audit_add_rule_data(audit_fd,
rule,
AUDIT_FILTER_USER,
AUDIT_ALWAYS);
int rc;
fd_set read_mask;
FD_ZERO(&read_mask);
FD_SET(audit_fd, &read_mask);
struct timeval t;
t.tv_sec = 0;
t.tv_usec = 300 * 1000;
do
{
rc = select(audit_fd+1, &read_mask, NULL, NULL, &t /*NULL*/);
struct audit_reply *rep = NULL;
audit_get_reply(audit_fd, rep, GET_REPLY_NONBLOCKING, 0);
if (rep != NULL)
{
printf("%s", rep->message);
break;
}
}
while (rc < 0);
audit_close(audit_fd);
This code does not work, it does not get reply from libaudit, what is wrong?
Actually, I need to get more information about user: who logged in, what he was running, what he was trying to change, etc.
I found a solution. Here is an example of the minimum working code.
The libaudit provides an interface for adding/removing rules:
int fd = audit_open();
struct audit_rule_data *rule = new audit_rule_data();
// what directory we will follow.
audit_add_watch_dir(AUDIT_DIR,
&rule,
"/etc");
// setting rule.
audit_add_rule_data(fd,
rule,
AUDIT_FILTER_EXIT,
AUDIT_ALWAYS);
// or removing rule.
audit_delete_rule_data(fd,
rule,
AUDIT_FILTER_EXIT,
AUDIT_ALWAYS);
audit_close(fd);
To set some specific event and set an additional filter you need to do something like this:
int fd = audit_open();
audit_rule_syscallbyname_data(rule_new, "open");
audit_rule_syscallbyname_data(rule_new, "close");
// Set extra filter, for example, follow the user with id=1000.
char pair[] = "uid=1000";
audit_rule_fieldpair_data(&rule_new, pair, AUDIT_FILTER_EXIT);
audit_add_rule_data(fd, rule_new, AUDIT_FILTER_EXIT, AUDIT_ALWAYS);
audit_close(fd);
To make an exception to the rules you need:
audit_rule_syscallbyname_data(rule, "mkdir");
char pair[] = "path=/etc";
audit_rule_fieldpair_data(&rule,
pair,
AUDIT_FILTER_EXIT);
audit_add_rule_data(fd,
rule,
AUDIT_FILTER_EXIT,
AUDIT_NEVER);
To receive messages from the audit:
void monitoring(struct ev_loop *loop, struct ev_io *io, int revents)
{
struct audit_reply reply;
audit_get_reply(fd, &reply, GET_REPLY_NONBLOCKING, 0);
if (reply.type != AUDIT_EOE &&
reply.type != AUDIT_PROCTITLE &&
reply.type != AUDIT_PATH)
{
char *buf = new char[MAX_AUDIT_MESSAGE_LENGTH];
snprintf(buf,
MAX_AUDIT_MESSAGE_LENGTH,
"Type=%s Message=%.*s",
audit_msg_type_to_name(reply.type),
reply.len,
reply.message);
printf("EVENT: %s\n", buf);
}
}
int main()
{
struct ev_io monitor;
fd = audit_open();
audit_set_pid(fd, getpid(), WAIT_YES);
loop = ev_default_loop(EVFLAG_NOENV);
ev_io_init(&monitor, monitoring, fd, EV_READ);
ev_io_start(loop, &monitor);
ev_loop(loop, 0);
audit_close(fd);
return 0;
}
UPD.
Your audit will not work if you do not write:
audit_set_enabled(audit_fd, 1);

Possible values of sa_family after calling getifaddrs

I have a code which listed interfaces on a device and looked for an interface of a given name and type:
ifaddrs * ifAddrs = nullptr;
getifaddrs(&ifAddrs);
for (ifaddrs * it = ifAddrs ; it != nullptr ; it = it->ifa_next)
{
if ((it->ifa_addr->sa_family == AF_INET) && (it->ifa_name == someInterfaceName))
{
// do stuff
}
}
Now I'd like to add IPv6 support and so I modified the code like this (added af variable):
ifaddrs * ifAddrs = nullptr;
getifaddrs(&ifAddrs);
int af = ipv6Code ? AF_INET : AF_INET6;
for (ifaddrs * it = ifAddrs ; it != nullptr ; it = it->ifa_next)
{
if ((it->ifa_addr->sa_family == af) && (it->ifa_name == someInterfaceName))
{
// do stuff
}
}
But I don't know if it's correct. Namely, if it->ifa_addr->sa_family can ever be AF_INET6 or if it's always AF_INET to describe an internet connection (regardless of IPv4 vs IPv6)? I found for instance this page: https://www.tutorialspoint.com/unix_sockets/socket_structures.htm which only lists AF_INET but then again this page: how to get IPV6 interface address using getifaddr() function uses AF_INET6. So which one is it?

Linked list sorting function in C++ doesn't stop properly

Many thanks in advance!
So, I've made attempts to make this function work. There are mistakes in the function but cannot catch them.
It seems to me, that I've missed the logic of sorting.
Could you point me 'where to go'?
/* node*/
typedef struct client {
int number; /* */
int balance;/* */
char lastName[20]; /* */
char firstName [20];/* */
char phone[11]; /* */
char email[20];
struct client *prev;/* */
struct client *next;
struct client *tmp; /* */
} Client;
Client *firstc,*currentc,*newc, *a, *b,*tmp; /*pointers*/
/* *"firstc' firstc element in list
*'currentc' current node
*'newc' new node
*'a' temporary pointer to Sort function
*'b' temporary pointer to Sort function
*'tmp' temporary pointer to Sort function
*/
int counter = 0;
int cnum = 0; /*cnum gives unique account numbers avoiding misentering*/
/*---Sort function------*/
void Sort()
{
/* */
int a = 0;/*variables to store balance*/
int b = 0;/*variables to store balance*/
if(firstc==NULL)
printf("Database is empty"); /*message*/
else
currentc = firstc;
currentc->prev = NULL;
tmp = NULL;
while((currentc=currentc->next)!= NULL)
{ /* 1) compare two nodes;
2) IF balance >*/
int a = currentc->balance;
int b = currentc->next->balance;/* debugger stopped here... */
if (a>b)
//if(currentc->balance >currentc->next->balance)
{ /*swap nodes*/
/*code using three pointers*/
tmp = currentc->next;
currentc->next->next = currentc->next;
currentc->next->next = tmp;
}
/*3)move along the list*/
else
currentc = currentc->next;
/*4) repeat to the end of list*/
}
currentc = firstc;
listAll();
return;
}
int b = currentc->next->balance;/* debugger stopped here... */
When currentc is pointing to the last item in the list currentc->next will be null. So currentc->next->balance is an access through a null pointer.
Also, practices like making assignments in conditions like while((currentc=currentc->next)!= NULL) will eventually come back to hurt you. In this case it seems you are skipping the first item in the list.
You probably meant:
if(firstc == NULL)
printf("Database is empty"); /*message*/
else
{ /* missing braces spotted by others */
currentc = firstc;
currentc->prev = NULL;
tmp = NULL;
for( ; currentc != NULL; currentc = currentc->next)
{
if(currentc->next == NUL)
/* nothing to compare */
break;
...
}
}
Furthermore the swapping code is swapping the wrong nodes:
tmp = currentc->next;
currentc->next->next = currentc->next;
currentc->next->next = tmp;
will almost (but not quite) swap the next node (b), with the one after it instead of with (a). You need to use the prev pointer (However since this looks like homework I had better not tell you exactly how to do it). Also, you are initialising prev but you need to keep it up to date in the loop. Actually, your 3 lines above are equivalent to:
tmp = currentc->next;
currentc->next->next = tmp;
so I think you meant something else.
the problem is when currentc is the last node, currectc->next is null, thus currentc->next->balance make it crash.
add some validation like
if (currentc->next == null)
and set b to a default/predefined value or put some logic whether you swap the nodes or not.

Struct linking to linked list

I am new to c++, and am trying to port a program i have made in python to c++. I have a struct that is a linked list with a list of parts. Each of these parts contains one or more components. So i have tried to create two structs, where one struct links to the other struct.
But i dont seem to get the list_part to link to component_list.
struct list_part {
char partname[100];
int parttype;
component_list * comp;
list_part * next;
};
struct component_list {
char compname[100];
component_list * next;
};
I use the following function to add the part to the bottom of the list.
void addpart(char partname[], int parttype, component_list *newcomp) {
struct list_part *temppart;
struct list_part *currentpart;
temppart = (struct list_part *)malloc(sizeof(struct list_part));
strcpy_s(temppart->partname,partname);
temppart->parttype = parttype;
temppart->comp = newcomp;
currentpart = head;
if (head == NULL) {
head = temppart;
head->next = NULL;
} else {
while (currentpart->next != NULL) {
currentpart = currentpart->next;
}
temppart->next = NULL;
currentpart->next = temppart;
}
}
And a similar function to add the component to a list.
void addcomp(char compname[]) {
struct component_list *tempcomp;
struct component_list *currentcomp;
tempcomp = (struct component_list *)malloc(sizeof(struct list_part));
strcpy_s(tempcomp->compname,compname);
currentcomp = newcomp;
if (currentcomp == NULL) {
currentcomp = tempcomp;
currentcomp->next = NULL;
} else {
while (currentcomp->next != NULL) {
currentcomp = currentcomp->next;
}
tempcomp->next = NULL;
currentcomp->next = tempcomp;
}
}
When the first component in a part is present i try to add it with.
struct component_list *newcomp = NULL;
strcpy_s(compname,temp.c_str());
addcomp(compname);
and the rest of the components i was planing to add with these commands
strcpy_s(compname,temp.c_str());
addcomp(compname);
And finally this is added as a part with
addpart(partname,fluidname, parttype, newcomp);
When i do it this way the newcomp only returns 00000000, but i need it to return a pointer to the list with components for this part. I have no idea how to do this really, i am used to dynamic languages, and this is not an issue there. I have figured this is the best way to go about this, but am very open to suggestions for other solutions. As data structures is something i am very fresh at.
Since you are open for suggestions, I think the best suggestion is You should be using std::list. instead of your own linked list implementaion.
std::list is a ready to use STL container provided by the C++ Standard library and it is always going to be more efficient that any list implementation you write.
You have 2 big mistakes in addcomp function, this should work: (also moved some things)
void addcomp(char compname[]) {
struct component_list *tempcomp;
struct component_list *currentcomp;
tempcomp = (struct component_list *)malloc(sizeof(struct component_list/*FIX 1*/));
strcpy_s(tempcomp->compname,compname);
tempcomp->next = NULL; /*Better do it here*/
if (newcomp == NULL) {
newcomp = tempcomp;/*FIX 2*/
} else {
currentcomp = newcomp; /*Better do it here*/
while (currentcomp->next != NULL) {
currentcomp = currentcomp->next;
}
currentcomp->next = tempcomp;
}
}

Why I got crash when allocating buffer?

I am developing a driver with Filter. So when I write the SendNetBufferListsComplete function in filter.cpp I got a crash (bluescreen). WinDbug pointed to some buffer allocation. The code is here:
Edited:
sendNetBufferListsComplete(
IN PNET_BUFFER_LIST NetBufferLists,
IN ULONG SendCompleteFlags) {
PNET_BUFFER_LIST pNetBufferList = NetBufferLists;
PNET_BUFFER_LIST pNextNetBufferList = NULL;
while (pNetBufferList)
{
pNextNetBufferList = NET_BUFFER_LIST_NEXT_NBL(pNetBufferList);
NET_BUFFER_LIST_NEXT_NBL(pNetBufferList) = NULL;
PNET_BUFFER_LIST pParentNetBufferList = pNetBufferList->ParentNetBufferList;
if (pParentNetBufferList != NULL)
{
NDIS_STATUS status = NET_BUFFER_LIST_STATUS(pNetBufferList);
NdisFreeNetBufferList(pNetBufferList);
if (NdisInterlockedDecrement(&pParentNetBufferList->ChildRefCount) == 0) {
NET_BUFFER_LIST_STATUS(pParentNetBufferList) = status;
NdisFSendNetBufferListsComplete(m_hFilter, pParentNetBufferList, SendCompleteFlags);
}
}
else
{
if(pNetBufferList != NULL)
{
**---windbug pointed here---****
PVOID pBuffer = *(PVOID*) NET_BUFFER_LIST_CONTEXT_DATA_START(pNetBufferList);
PMDL pMdl = NET_BUFFER_FIRST_MDL(NET_BUFFER_LIST_FIRST_NB(pNetBufferList));
if(pMdl)
NdisFreeMdl(pMdl);
if(pBuffer)
delete[] (UCHAR*) pBuffer;
NdisFreeNetBufferList(pNetBufferList);
}
}
NdisInterlockedDecrement(&m_nSendNetBufferListCount);
pNetBufferList = pNextNetBufferList;
}
What is the actual problem? Is it overflow? Or NULL check problems?
In ndish.h
#define NET_BUFFER_LIST_CONTEXT_DATA_START(_NBL) ((PUCHAR)(((_NBL)->Context)+1)+(_NBL)->Context->Offset)
like this . and in Wdm.h
//
// I/O system definitions.
//
// Define a Memory Descriptor List (MDL)
//
// An MDL describes pages in a virtual buffer in terms of physical pages. The
// pages associated with the buffer are described in an array that is allocated
// just after the MDL header structure itself.
//
typedef
_Struct_size_bytes_(_Inexpressible_(sizeof(struct _MDL) + // 747934
(ByteOffset + ByteCount + PAGE_SIZE-1) / PAGE_SIZE * sizeof(PFN_NUMBER)))
struct _MDL {
struct _MDL *Next;
CSHORT Size;
CSHORT MdlFlags;
struct _EPROCESS *Process;
PVOID MappedSystemVa; /* see creators for field size annotations. */
PVOID StartVa; /* see creators for validity; could be address 0. */
ULONG ByteCount;
ULONG ByteOffset;
} MDL, *PMDL;