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?
Related
I am using IXGBE Nic, using dpdk 19.11 multi rx queue with rss "ETH_RSS_TCP | ETH_RSS_IP".
IXGBE support max 64 queues, and i used 4 queues. But all packages arrvied to the same queue(queue 0), it seems rss function not work well.
The following is the pseudo code of my rss part. Is the rss function not taking effect due to my incorrect configuration?
static int rss_setup(const int port_id, const uint16_t nb_queues)
{
int i;
int ret;
struct rte_eth_dev_info dev_info;
struct rte_eth_rss_reta_entry64 *reta_conf = NULL;
rte_eth_dev_info_get(port_id, &dev_info);
if (nb_queues == 0) {
return ERR_VAL;
}
reta_conf = calloc(dev_info.reta_size / RTE_RETA_GROUP_SIZE,
sizeof(struct rte_eth_rss_reta_entry64));
if (!reta_conf) {
return ERR_MEM;
}
for (i = 0; i < dev_info.reta_size; i++) {
struct rte_eth_rss_reta_entry64 *one_reta_conf =
&reta_conf[i / RTE_RETA_GROUP_SIZE];
one_reta_conf->reta[i % RTE_RETA_GROUP_SIZE] = i % nb_queues;
}
for (i = 0; i < dev_info.reta_size / RTE_RETA_GROUP_SIZE; i++) {
struct rte_eth_rss_reta_entry64 *one_reta_conf = &reta_conf[i];
one_reta_conf->mask = 0xFFFFFFFFFFFFFFFFULL;
}
ret = rte_eth_dev_rss_reta_update(port_id, reta_conf, dev_info.reta_size);
if (ret < 0) {
printf("cannot update rss reta at port %d: %s\n",
port_id, rte_strerror(-ret));
}
free(reta_conf);
return ERR_OK;
}
main (){
struct rte_eth_conf conf = {0};
conf.link_speeds = ETH_LINK_SPEED_AUTONEG;
conf.txmode.mq_mode = ETH_MQ_TX_NONE;
conf.rxmode.mq_mode = ETH_MQ_RX_NONE;
struct rte_eth_dev_info dev_info;
rte_eth_dev_info_get(port_id, &dev_info);
int rss_enable = 0;
uint64_t def_rss_hf = ETH_RSS_TCP | ETH_RSS_IP;
struct rte_eth_rss_conf rss_conf = {
NULL,
40,
def_rss_hf,
};
rss_conf.rss_hf &= dev_info->flow_type_rss_offloads;
if (rss_conf.rss_hf) {
rss_enable = 1;
conf->rx_adv_conf.rss_conf = rss_conf;
conf->rxmode.mq_mode = ETH_MQ_RX_RSS;
rss_setup(port_id, 4); // queues cnt is 4
}
}
Looks like the program does not invoke rte_eth_dev_configure() before invoking rss_setup(). This is not correct as rte_eth_dev_configure() "must be invoked first before any other function in the Ethernet API" (doc reference). Please re-arrange the program to first invoke rte_eth_dev_configure() with rx_adv_conf.rss_conf and ETH_MQ_RX_RSS specified, then proceed with the rest of bring-up.
In rss_setup(), the program invokes rte_eth_dev_rss_reta_update(). For the PMD in question, this API can only be invoked in started state (code reference). So please re-arrange the program a bit more to invoke rte_eth_dev_start() before rss_setup().
Please make sure that TCP source port numbers (and/or IP source addresses) are randomised at the sender side. If IP/TCP source and destination fields do not vary, it's no surprise that the packets end up in the same Rx queue.
I'm trying to programmatically determine the filename and line of the source code for a function definition using its address and the pdb database file generated by visual studio for the module the function is defined in.
For instance, I have a function Lua::asset::get_supported_export_file_extensions defined in the module shared.dll and I want to determine the source code location for it.
To get the relative virtual address (rva) of the function, I subtract the module base address from the absolute virtual function address like so:
static MODULEENTRY32 GetModuleInfo(std::uint32_t ProcessID, const char* ModuleName)
{
void* hSnap = nullptr;
MODULEENTRY32 Mod32 = {0};
if ((hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, ProcessID)) == INVALID_HANDLE_VALUE)
return Mod32;
Mod32.dwSize = sizeof(MODULEENTRY32);
while (Module32Next(hSnap, &Mod32))
{
if (!strcmp(ModuleName, Mod32.szModule))
{
CloseHandle(hSnap);
return Mod32;
}
}
CloseHandle(hSnap);
return {0};
}
int main(int argc,char *argv[])
{
auto dllInfo = GetModuleInfo(GetCurrentProcessId(),"shared.dll");
auto rva = (DWORD)((uint64_t)&Lua::asset::get_supported_export_file_extensions -(uint64_t)dllInfo.modBaseAddr);
[...]
}
This gives me the rva 0x44508 for the function.
To confirm the address, I've tried using the dbh debugging tool from the Windows SDK to look up the function's address (as well as the base address for the module):
shared [1000000]: enum shared!*get_supported_export_file_extensions*
index address name
1 1e376c0 : `Lua::asset::get_supported_export_file_extensions'::`1'::dtor$0
3 18409c0 : Lua::asset::get_supported_export_file_extensions
shared [1000000]: scope 18409c0
name : path\to\object_files\lasset.obj
addr : 0
size : 0
flags : 0
type : 0
modbase : 1000000
value : 0
reg : 0
scope : SymTagNull (0)
tag : SymTagCompiland (2)
index : 6
I would expect it to give me the same rva if I subtract the base address from the function address, but instead it gives me a rva of 0x18409c0 -0x1000000 = 0x8409c0
For convenience I will be referring to the addresses as:
0x44508 = calculated address
0x8409c0 = dbh address
I then used the Debug Interface Access SDK to look up both addresses in the pdb to determine why I'm getting differing results:
static BOOL find_function_in_pdb(DWORD rva,enum SymTagEnum tag)
{
std::string pdbFilePath = "path/to/shared.pdb";
CComPtr<IDiaDataSource> pSource;
if(FAILED(CoInitializeEx(NULL,COINIT_MULTITHREADED)))
return FALSE;
auto hr = CoCreateInstance(
CLSID_DiaSource,
NULL,
CLSCTX_INPROC_SERVER,
__uuidof(IDiaDataSource),
(void **) &pSource
);
if(FAILED(hr))
return FALSE;
wchar_t wszFilename[_MAX_PATH];
mbstowcs(wszFilename,pdbFilePath.data(),sizeof(wszFilename) /sizeof(wszFilename[0]));
if(FAILED(pSource->loadDataFromPdb(wszFilename)))
return FALSE;
IDiaSession *session;
IDiaSymbol *globalSymbol = nullptr;
IDiaEnumTables *enumTables = nullptr;
IDiaEnumSymbolsByAddr *enumSymbolsByAddr = nullptr;
if(FAILED(pSource->openSession(&session)))
return FALSE;
if(FAILED(session->get_globalScope(&globalSymbol)))
return FALSE;
if(FAILED(session->getEnumTables(&enumTables)))
return FALSE;
if(FAILED(session->getSymbolsByAddr(&enumSymbolsByAddr)))
return FALSE;
IDiaSymbol *symbol;
if(session->findSymbolByRVA(rva,tag,&symbol) == S_OK)
{
BSTR name;
symbol->get_name(&name);
std::cout<<"Name: "<<ConvertBSTRToMBS(name)<<std::endl;
ULONGLONG length = 0;
if(symbol->get_length(&length) == S_OK)
{
IDiaEnumLineNumbers *lineNums[100];
if(session->findLinesByRVA(rva,length,lineNums) == S_OK)
{
auto &l = lineNums[0];
CComPtr<IDiaLineNumber> line;
IDiaLineNumber *lineNum;
ULONG fetched = 0;
for(uint8_t i=0;i<5;++i) {
if(l->Next(i,&lineNum,&fetched) == S_OK && fetched == 1)
{
DWORD l;
IDiaSourceFile *srcFile;
if(lineNum->get_sourceFile(&srcFile) == S_OK)
{
BSTR fileName;
srcFile->get_fileName(&fileName);
std::cout<<"File: "<<ConvertBSTRToMBS(fileName)<<std::endl;
}
if(lineNum->get_lineNumber(&l) == S_OK)
std::cout<<"Line: "<<+l<<std::endl;
}
}
}
}
}
return TRUE;
}
int main(int argc,char *argv[])
{
find_function_in_pdb(0x44508 /* calculated address */,SymTagEnum::SymTagPublicSymbol);
find_function_in_pdb(0x8409c0 /* dbh address */,SymTagEnum::SymTagFunction);
[...]
}
It does actually find both addresses and both point to a symbol with a name matching my function, however the symbol at the calculated address is a SymTagPublicSymbol and the symbol at the dbh address is a SymTagFunction.
I'm guessing that means that the calculated address is for the public symbol and the dbh address for the private symbol? (https://learn.microsoft.com/en-us/windows-hardware/drivers/debugger/public-and-private-symbols)
So far so good, the problem is the public symbol does not have any source code information associated with it, but the private symbol does. Assuming I'm correct so far (which I'm not quite sure about), my question boils down to:
How can I get the private symbol/address from the public symbol/address? I need a solution that I can implement programmatically.
After some more experimentation I found the solution:
IDiaSymbol *publicSymbol;
DWORD publicRva = 0x44508;
if(session->findSymbolByRVA(publicRva,SymTagEnum::SymTagPublicSymbol,&publicSymbol) == S_OK)
{
DWORD privateRva;
IDiaSymbol *privateSymbol;
if(
publicSymbol->get_targetRelativeVirtualAddress(&privateRva) == S_OK &&
session->findSymbolByRVA(privateRva,SymTagEnum::SymTagFunction,&privateSymbol) == S_OK
)
{
// Do stuff with private symbol
}
}
get_targetRelativeVirtualAddress gives me 0x8409c0, the address of the private symbol which contains the source code information.
As for why this works, I have no idea. According to the documentation, get_targetRelativeVirtualAddress is only supposed to be valid for SymTagThunk symbols and returns the rva of a "thunk target". I don't think the public symbol is a thunk target, but it works without errors and gives me exactly what I need.
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);
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];
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;
}
}