dsyleixa123
Posts: 1482
Joined: Mon Jun 11, 2018 11:22 am

C++ functions to retrieve and set IPs a/o SSIDs in the local home network?

Sun May 09, 2021 11:14 am

hi,
which would be the C/C++ functions to retrieve and set IPs (IPv4) a/o SSIDs in the local home network, to be used inside of a C++ program?
e.g.,
get current router IP (e.g., 192.168.1.1)
get current router SSID (e.g., WLAN123456)
get current local Raspi IP (e.g., 192.168.1.103)
change/set local Raspi IP (to e.g., 192.168.1.100) and reconnect
retrieve all currently available router SSIDs
connect arbitrarily to a different router (by SSID+pwd)
check router connection
:?:
(I want to store all data in variables for further processing)
Last edited by dsyleixa123 on Wed May 12, 2021 1:51 pm, edited 2 times in total.

User avatar
DougieLawson
Posts: 41316
Joined: Sun Jun 16, 2013 11:19 pm
Location: A small cave in deepest darkest Basingstoke, UK
Contact: Website Twitter

Re: C++ code to retrieve and set IPs a/o SSIDs in the local home network?

Sun May 09, 2021 3:41 pm

This code gets the IPv4 address

Code: Select all

char* getIPaddr()
{
  struct ifaddrs* interfaceArray = NULL, *tempIfAddr = NULL;
  void* tempAddrPtr = NULL;
  int rc = 0;
  char addressOutputBuffer[INET6_ADDRSTRLEN];
  char* ifaceIP = malloc (40);

  rc = getifaddrs(&interfaceArray);	/* retrieve the current interfaces */
  if (rc == 0)
    {
      for (tempIfAddr = interfaceArray; tempIfAddr != NULL;
	   tempIfAddr = tempIfAddr->ifa_next)
	{
	  if (tempIfAddr->ifa_addr->sa_family == AF_INET)
	    {
	      tempAddrPtr =
		&((struct sockaddr_in*) tempIfAddr->ifa_addr)->sin_addr;

	      if (strncmp (tempIfAddr->ifa_name, "lo", 2))	/* interface ISN'T loopback */
		{
		  inet_ntop (tempIfAddr->ifa_addr->sa_family, tempAddrPtr,
			     addressOutputBuffer,
			     sizeof (addressOutputBuffer));
		  sprintf (ifaceIP, "%s %s\0", tempIfAddr->ifa_name,
			   addressOutputBuffer);
		}
	    }
	}

      freeifaddrs (interfaceArray);	/* free the dynamic memory */
      interfaceArray = NULL;	/* prevent use after free  */
    }
  else
    {
      printf ("getifaddrs() failed with errno =  %d %s \0",
	      errno, strerror (errno));
    }

  return ifaceIP;
}
To set an IP address steal the code from the ip command or test if https://stackoverflow.com/a/6940391/3491475 works.
Any language using left-hand whitespace for syntax is ridiculous

Any DMs sent on Twitter will be answered next month.
Fake doctors - are all on my foes list.

Any requirement to use a crystal ball or mind reading will result in me ignoring your question.

cleverca22
Posts: 3801
Joined: Sat Aug 18, 2012 2:33 pm

Re: C++ code to retrieve and set IPs a/o SSIDs in the local home network?

Sun May 09, 2021 4:02 pm

dsyleixa123 wrote:
Sun May 09, 2021 11:14 am
get current router SSID (e.g., WLAN123456)

Code: Select all

root@pi400:~# wpa_cli -i wlan0 status | egrep ^ssid
ssid=TP-LINK_Extender_5GHz
dsyleixa123 wrote:
Sun May 09, 2021 11:14 am
retrieve all currently available router SSIDs

Code: Select all

root@pi400:~# wpa_cli -i wlan0 scan
OK
root@pi400:~# wpa_cli -i wlan0 scan_results
bssid / frequency / signal level / flags / ssid
d8:0d:17:x       5180    -40     [WPA-PSK-CCMP+TKIP][WPA2-PSK-CCMP+TKIP][WPS][ESS]       TP-LINK_Extender_5GHz
d8:0d:17:x       2457    -29     [WPA-PSK-CCMP+TKIP][WPA2-PSK-CCMP+TKIP][WPS][ESS]       TP-LINK_Extender_2.4GHz
4c:8b:30:x       2462    -51     [WPA-PSK-CCMP][WPA2-PSK-CCMP][ESS]      FIBREOP038
28:c2:dd:x       2442    -56     [WPA2-PSK-TKIP][ESS]    Family-nas
f8:ab:05:x       2462    -73     [WPA2-PSK-CCMP][WPS][ESS]       BELL220
00:fc:8d:x       2462    -80     [WPA-PSK-CCMP][WPA2-PSK-CCMP][WPS][ESS] Simmons
5c:7d:7d:x       5220    -90     [WPA2-PSK-CCMP][ESS]
you need a bit of a delay between scan and scan_results

Code: Select all

root@pi400:~# wpa_cli -i wlan0 list_networks
network id / ssid / bssid / flags
0       TP-LINK_Extender_5GHz   any     [CURRENT]
1       Alexander-5G    any
2       TP-LINK_Extender_2.4GHz any
root@pi400:~# wpa_cli -i wlan0 select_network 2
this lets you force a certain network, if its already been added

dsyleixa123
Posts: 1482
Joined: Mon Jun 11, 2018 11:22 am

Re: C++ code to retrieve and set IPs a/o SSIDs in the local home network?

Sun May 09, 2021 4:35 pm

thank you!

@ DougieLawson: what do you mean by "steal the code from the ip command"?
OTOH, the code at the link is no C code which I know how to use, tbh...

@ cleverca22: is that C/C++ code at all?

(I want to store all data in variables for further processing)

User avatar
DougieLawson
Posts: 41316
Joined: Sun Jun 16, 2013 11:19 pm
Location: A small cave in deepest darkest Basingstoke, UK
Contact: Website Twitter

Re: C++ code to retrieve and set IPs a/o SSIDs in the local home network?

Sun May 09, 2021 4:49 pm

dsyleixa123 wrote:
Sun May 09, 2021 4:35 pm

@ DougieLawson: what do you mean by steal the code from the ip command?
OTOH, the code at the link is no C code which I know how to use, tbh...
Take a look at the source for for the IP command and see how it sets an IP address.
https://mirrors.edge.kernel.org/pub/lin ... 9.0.tar.xz

The stack overflow posting has an example program

Code: Select all

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stddef.h>             /* offsetof */
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <linux/sockios.h>
#include <netinet/in.h>
#if __GLIBC__ >=2 && __GLIBC_MINOR >= 1
#include <netpacket/packet.h>
#include <net/ethernet.h>
#else
#include <asm/types.h>
#include <linux/if_ether.h>
#endif

#define IFNAME "eth0:2"
#define HOST "192.168.3.135"
#define ifreq_offsetof(x)  offsetof(struct ifreq, x)

int main(int argc, char **argv) {

        struct ifreq ifr;
        struct sockaddr_in sai;
        int sockfd;                     /* socket fd we use to manipulate stuff with */
        int selector;
        unsigned char mask;
        int rc;
        char *p;


        /* Create a channel to the NET kernel. */
        sockfd = socket(AF_INET, SOCK_DGRAM, 0);

        /* get interface name */
        strncpy(ifr.ifr_name, IFNAME, IFNAMSIZ);

        memset(&sai, 0, sizeof(struct sockaddr));
        sai.sin_family = AF_INET;
        sai.sin_port = 0;

        sai.sin_addr.s_addr = inet_addr(HOST);

        p = (char *) &sai;
        memcpy( (((char *)&ifr + ifreq_offsetof(ifr_addr) )),
                        p, sizeof(struct sockaddr));

        rc=ioctl(sockfd, SIOCSIFADDR, &ifr);
        printf("SIOCSIFADDR rc %d\n", rc);
        rc=ioctl(sockfd, SIOCGIFFLAGS, &ifr);
        printf("SIOCSIFFLAGS rc %d\n", rc);

        ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
        // ifr.ifr_flags &= ~selector;  // unset something

        rc=ioctl(sockfd, SIOCSIFFLAGS, &ifr);
        printf("SIOCSIFFLAGS rc %d\n", rc);
        close(sockfd);
        return 0;
}


that needs to run with sudo that creates an eth0:2 interface and assigns 192.168.1.204 to it.
Last edited by DougieLawson on Sun May 09, 2021 4:58 pm, edited 1 time in total.
Any language using left-hand whitespace for syntax is ridiculous

Any DMs sent on Twitter will be answered next month.
Fake doctors - are all on my foes list.

Any requirement to use a crystal ball or mind reading will result in me ignoring your question.

dsyleixa123
Posts: 1482
Joined: Mon Jun 11, 2018 11:22 am

Re: C++ code to retrieve and set IPs a/o SSIDs in the local home network?

Sun May 09, 2021 4:56 pm

thanks try it ASAP.

as to your 1st code: I can't compile it (I use g++):

Code: Select all

#include <stdio.h>
#include <string.h>
#include <errno.h>

char* getIPaddr()
{
  struct ifaddrs* interfaceArray = NULL, *tempIfAddr = NULL;
  void* tempAddrPtr = NULL;
  int rc = 0;
  char addressOutputBuffer[INET6_ADDRSTRLEN];
  char* ifaceIP = malloc (40);

  rc = getifaddrs(&interfaceArray);	/* retrieve the current interfaces */
  if (rc == 0)
    {
      for (tempIfAddr = interfaceArray; tempIfAddr != NULL;
	   tempIfAddr = tempIfAddr->ifa_next)
	{
	  if (tempIfAddr->ifa_addr->sa_family == AF_INET)
	    {
	      tempAddrPtr =
		&((struct sockaddr_in*) tempIfAddr->ifa_addr)->sin_addr;

	      if (strncmp (tempIfAddr->ifa_name, "lo", 2))	/* interface ISN'T loopback */
		{
		  inet_ntop (tempIfAddr->ifa_addr->sa_family, tempAddrPtr,
			     addressOutputBuffer,
			     sizeof (addressOutputBuffer));
		  sprintf (ifaceIP, "%s %s\0", tempIfAddr->ifa_name,
			   addressOutputBuffer);
		}
	    }
	}

      freeifaddrs (interfaceArray);	/* free the dynamic memory */
      interfaceArray = NULL;	/* prevent use after free  */
    }
  else
    {
      printf ("getifaddrs() failed with errno =  %d %s \0",
	      errno, strerror (errno));
    }

  return ifaceIP;
}


#include <stdio.h>

int main(int argc, char **argv)
{
    char IPaddr[16]; //192.168.111.222 len=15+1
	
    strcpy(IPaddr, getIPaddr() );
    printf("%s", IPaddr);
    
    char c=getchar();
    
	return 0;
}


Code: Select all

g++ -Wall -I/opt/vc/include -c  "IPaddr001.c" -pthread -I/opt/vc/include -lshapes -lwiringPi -lpigpio -lrt $(pkg-config eigen3 --cflags) -lreadline (im Verzeichnis: /home/pi/raspiProgs/internet)
IPaddr001.c: In function ‘char* getIPaddr()’:
IPaddr001.c:10:28: error: ‘INET6_ADDRSTRLEN’ was not declared in this scope
   char addressOutputBuffer[INET6_ADDRSTRLEN];
                            ^~~~~~~~~~~~~~~~
IPaddr001.c:11:29: error: ‘malloc’ was not declared in this scope
   char* ifaceIP = malloc (40);
                             ^
IPaddr001.c:13:34: error: ‘getifaddrs’ was not declared in this scope
   rc = getifaddrs(&interfaceArray); /* retrieve the current interfaces */
                                  ^
IPaddr001.c:17:28: error: invalid use of incomplete type ‘struct getIPaddr()::ifaddrs’
     tempIfAddr = tempIfAddr->ifa_next)
                            ^~
IPaddr001.c:7:10: note: forward declaration of ‘struct getIPaddr()::ifaddrs’
   struct ifaddrs* interfaceArray = NULL, *tempIfAddr = NULL;
          ^~~~~~~
IPaddr001.c:19:18: error: invalid use of incomplete type ‘struct getIPaddr()::ifaddrs’
    if (tempIfAddr->ifa_addr->sa_family == AF_INET)
                  ^~
IPaddr001.c:7:10: note: forward declaration of ‘struct getIPaddr()::ifaddrs’
   struct ifaddrs* interfaceArray = NULL, *tempIfAddr = NULL;
          ^~~~~~~
IPaddr001.c:19:43: error: ‘AF_INET’ was not declared in this scope
    if (tempIfAddr->ifa_addr->sa_family == AF_INET)
                                           ^~~~~~~
IPaddr001.c:22:37: error: invalid use of incomplete type ‘struct getIPaddr()::ifaddrs’
   &((struct sockaddr_in*) tempIfAddr->ifa_addr)->sin_addr;
                                     ^~
IPaddr001.c:7:10: note: forward declaration of ‘struct getIPaddr()::ifaddrs’
   struct ifaddrs* interfaceArray = NULL, *tempIfAddr = NULL;
          ^~~~~~~
IPaddr001.c:24:31: error: invalid use of incomplete type ‘struct getIPaddr()::ifaddrs’
        if (strncmp (tempIfAddr->ifa_name, "lo", 2)) /* interface ISN'T loopback */
                               ^~
IPaddr001.c:7:10: note: forward declaration of ‘struct getIPaddr()::ifaddrs’
   struct ifaddrs* interfaceArray = NULL, *tempIfAddr = NULL;
          ^~~~~~~
IPaddr001.c:26:26: error: invalid use of incomplete type ‘struct getIPaddr()::ifaddrs’
     inet_ntop (tempIfAddr->ifa_addr->sa_family, tempAddrPtr,
                          ^~
IPaddr001.c:7:10: note: forward declaration of ‘struct getIPaddr()::ifaddrs’
   struct ifaddrs* interfaceArray = NULL, *tempIfAddr = NULL;
          ^~~~~~~
IPaddr001.c:27:9: error: ‘addressOutputBuffer’ was not declared in this scope
         addressOutputBuffer,
         ^~~~~~~~~~~~~~~~~~~
IPaddr001.c:28:37: error: ‘inet_ntop’ was not declared in this scope
         sizeof (addressOutputBuffer));
                                     ^
IPaddr001.c:29:44: error: invalid use of incomplete type ‘struct getIPaddr()::ifaddrs’
     sprintf (ifaceIP, "%s %s\0", tempIfAddr->ifa_name,
                                            ^~
IPaddr001.c:7:10: note: forward declaration of ‘struct getIPaddr()::ifaddrs’
   struct ifaddrs* interfaceArray = NULL, *tempIfAddr = NULL;
          ^~~~~~~
IPaddr001.c:35:34: error: ‘freeifaddrs’ was not declared in this scope
       freeifaddrs (interfaceArray); /* free the dynamic memory */
                                  ^
IPaddr001.c:41:31: warning: embedded ‘\0’ in format [-Wformat-contains-nul]
        errno, strerror (errno));
                               ^
IPaddr001.c: In function ‘int main(int, char**)’:
IPaddr001.c:57:10: warning: unused variable ‘c’ [-Wunused-variable]
     char c=getchar();
          ^
Kompilierung fehlgeschlagen.


User avatar
DougieLawson
Posts: 41316
Joined: Sun Jun 16, 2013 11:19 pm
Location: A small cave in deepest darkest Basingstoke, UK
Contact: Website Twitter

Re: C++ code to retrieve and set IPs a/o SSIDs in the local home network?

Sun May 09, 2021 4:59 pm

I've updated it to suppress the warnings.

It's C so compile with gcc -o ipaddup ipaddup.c
Run it with sudo ./ipaddup
Any language using left-hand whitespace for syntax is ridiculous

Any DMs sent on Twitter will be answered next month.
Fake doctors - are all on my foes list.

Any requirement to use a crystal ball or mind reading will result in me ignoring your question.

dsyleixa123
Posts: 1482
Joined: Mon Jun 11, 2018 11:22 am

Re: C++ code to retrieve and set IPs a/o SSIDs in the local home network?

Sun May 09, 2021 5:02 pm

I always need g++ because I always include C++ libs additionally (and it also will have to run as a function in qt creator).

will try the updated code now...

(edit: just now noticed that you didn't change your 1st code yet which I am currently using...)
Last edited by dsyleixa123 on Sun May 09, 2021 5:17 pm, edited 1 time in total.

dsyleixa123
Posts: 1482
Joined: Mon Jun 11, 2018 11:22 am

Re: C++ code to retrieve and set IPs a/o SSIDs in the local home network?

Sun May 09, 2021 5:04 pm

Code: Select all

#include <stdio.h>
#include <string.h>
#include <errno.h>

char* getIPaddr()
{
  struct ifaddrs* interfaceArray = NULL, *tempIfAddr = NULL;
  void* tempAddrPtr = NULL;
  int rc = 0;
  char addressOutputBuffer[INET6_ADDRSTRLEN];
  char* ifaceIP = malloc (40);

  rc = getifaddrs(&interfaceArray);	/* retrieve the current interfaces */
  if (rc == 0)
    {
      for (tempIfAddr = interfaceArray; tempIfAddr != NULL;
	   tempIfAddr = tempIfAddr->ifa_next)
	{
	  if (tempIfAddr->ifa_addr->sa_family == AF_INET)
	    {
	      tempAddrPtr =
		&((struct sockaddr_in*) tempIfAddr->ifa_addr)->sin_addr;

	      if (strncmp (tempIfAddr->ifa_name, "lo", 2))	/* interface ISN'T loopback */
		{
		  inet_ntop (tempIfAddr->ifa_addr->sa_family, tempAddrPtr,
			     addressOutputBuffer,
			     sizeof (addressOutputBuffer));
		  sprintf (ifaceIP, "%s %s\0", tempIfAddr->ifa_name,
			   addressOutputBuffer);
		}
	    }
	}

      freeifaddrs (interfaceArray);	/* free the dynamic memory */
      interfaceArray = NULL;	/* prevent use after free  */
    }
  else
    {
      printf ("getifaddrs() failed with errno =  %d %s \0",
	      errno, strerror (errno));
    }

  return ifaceIP;
}



int main()
{
    char IPaddr[16]; //192.168.xxx.yyy len=15+1
	
    strncpy(IPaddr, getIPaddr(), 15);
    printf("%s", IPaddr);
    
    char c=getchar();
    
    return 0;
}

Code: Select all

g++ -Wall -I/opt/vc/include -o  "IPaddr_read001" "IPaddr_read001.c" -pthread -I/opt/vc/include -lshapes -lwiringPi -lpigpio -lrt $(pkg-config eigen3 --cflags) -lreadline  (im Verzeichnis: /home/pi/raspiProgs/internet)
IPaddr_read001.c: In function ‘char* getIPaddr()’:
IPaddr_read001.c:10:28: error: ‘INET6_ADDRSTRLEN’ was not declared in this scope
   char addressOutputBuffer[INET6_ADDRSTRLEN];
                            ^~~~~~~~~~~~~~~~
IPaddr_read001.c:11:29: error: ‘malloc’ was not declared in this scope
   char* ifaceIP = malloc (40);
                             ^
IPaddr_read001.c:13:34: error: ‘getifaddrs’ was not declared in this scope
   rc = getifaddrs(&interfaceArray); /* retrieve the current interfaces */
                                  ^
IPaddr_read001.c:17:28: error: invalid use of incomplete type ‘struct getIPaddr()::ifaddrs’
     tempIfAddr = tempIfAddr->ifa_next)
                            ^~
IPaddr_read001.c:7:10: note: forward declaration of ‘struct getIPaddr()::ifaddrs’
   struct ifaddrs* interfaceArray = NULL, *tempIfAddr = NULL;
          ^~~~~~~
IPaddr_read001.c:19:18: error: invalid use of incomplete type ‘struct getIPaddr()::ifaddrs’
    if (tempIfAddr->ifa_addr->sa_family == AF_INET)
                  ^~
IPaddr_read001.c:7:10: note: forward declaration of ‘struct getIPaddr()::ifaddrs’
   struct ifaddrs* interfaceArray = NULL, *tempIfAddr = NULL;
          ^~~~~~~
IPaddr_read001.c:19:43: error: ‘AF_INET’ was not declared in this scope
    if (tempIfAddr->ifa_addr->sa_family == AF_INET)
                                           ^~~~~~~
IPaddr_read001.c:22:37: error: invalid use of incomplete type ‘struct getIPaddr()::ifaddrs’
   &((struct sockaddr_in*) tempIfAddr->ifa_addr)->sin_addr;
                                     ^~
IPaddr_read001.c:7:10: note: forward declaration of ‘struct getIPaddr()::ifaddrs’
   struct ifaddrs* interfaceArray = NULL, *tempIfAddr = NULL;
          ^~~~~~~
IPaddr_read001.c:24:31: error: invalid use of incomplete type ‘struct getIPaddr()::ifaddrs’
        if (strncmp (tempIfAddr->ifa_name, "lo", 2)) /* interface ISN'T loopback */
                               ^~
IPaddr_read001.c:7:10: note: forward declaration of ‘struct getIPaddr()::ifaddrs’
   struct ifaddrs* interfaceArray = NULL, *tempIfAddr = NULL;
          ^~~~~~~
IPaddr_read001.c:26:26: error: invalid use of incomplete type ‘struct getIPaddr()::ifaddrs’
     inet_ntop (tempIfAddr->ifa_addr->sa_family, tempAddrPtr,
                          ^~
IPaddr_read001.c:7:10: note: forward declaration of ‘struct getIPaddr()::ifaddrs’
   struct ifaddrs* interfaceArray = NULL, *tempIfAddr = NULL;
          ^~~~~~~
IPaddr_read001.c:27:9: error: ‘addressOutputBuffer’ was not declared in this scope
         addressOutputBuffer,
         ^~~~~~~~~~~~~~~~~~~
IPaddr_read001.c:28:37: error: ‘inet_ntop’ was not declared in this scope
         sizeof (addressOutputBuffer));
                                     ^
IPaddr_read001.c:29:44: error: invalid use of incomplete type ‘struct getIPaddr()::ifaddrs’
     sprintf (ifaceIP, "%s %s\0", tempIfAddr->ifa_name,
                                            ^~
IPaddr_read001.c:7:10: note: forward declaration of ‘struct getIPaddr()::ifaddrs’
   struct ifaddrs* interfaceArray = NULL, *tempIfAddr = NULL;
          ^~~~~~~
IPaddr_read001.c:35:34: error: ‘freeifaddrs’ was not declared in this scope
       freeifaddrs (interfaceArray); /* free the dynamic memory */
                                  ^
IPaddr_read001.c:41:31: warning: embedded ‘\0’ in format [-Wformat-contains-nul]
        errno, strerror (errno));
                               ^
IPaddr_read001.c: In function ‘int main(int, char**)’:
IPaddr_read001.c:56:10: warning: unused variable ‘c’ [-Wunused-variable]
     char c=getchar();
          ^
Kompilierung fehlgeschlagen.



cleverca22
Posts: 3801
Joined: Sat Aug 18, 2012 2:33 pm

Re: C++ code to retrieve and set IPs a/o SSIDs in the local home network?

Sun May 09, 2021 5:17 pm

dsyleixa123 wrote:
Sun May 09, 2021 4:35 pm
@ cleverca22: is that C/C++ code at all?
the example i gave was just raw shell commands, but you can access wpa_cli over a unix socket too

Code: Select all

#include <QString>
#include <sys/types.h>
#include <sys/socket.h>
#include <QDebug>
#include <sys/un.h>
#include <QTimer>
#include <QTime>
#include "wpa_client.h"

int connect_proxy(int fd,sockaddr *addr,int size) {
	return connect(fd,addr,size);
}
wpa_client::wpa_client(QString interface) {
	this->interface = interface;
	pinger = new QTimer(this);
	connect(pinger,SIGNAL(timeout()),this,SLOT(ping_it()));
	pinger->start(5000);
	connected = false;
}
void wpa_client::ping_it() {
	if ((!connected) && (fd > 0)) {
		if (try_connect()) return;
	} else send_msg("PING");
}
void wpa_client::connect_wpa() {
	fd = socket(PF_FILE,SOCK_DGRAM,0);
	if (!fd) return;
	struct sockaddr_un self;
	self.sun_family = AF_FILE;
	strncpy(self.sun_path,"/tmp/wpa_client",100);
	unlink("/tmp/wpa_client");
	if (bind(fd,(sockaddr*)&self,sizeof(self))) {
		qDebug("err1");
		return;
	}
	start();
	if (try_connect()) return;
}
bool wpa_client::try_connect() {
	struct sockaddr_un target;
	target.sun_family = AF_FILE;
	strncpy(target.sun_path,qPrintable(QString("/var/run/wpa_supplicant/wlan0")),100);
	if (connect_proxy(fd,(sockaddr*)&target,sizeof(target))) {
		qDebug() << QString("err2 %1").arg(fd);
		return true;
	}
	qDebug() << "connected?";
	if (send_msg("ATTACH")) {
		return true;
	}
	qDebug() << "attached";
	connected = true;
	return false;
}
bool wpa_client::send_msg(QString msg) {
	if (fd < 0) return true;
	const char *buffer;
	buffer = qPrintable(msg);
	int length = strlen(buffer);
	int ret = send(fd,buffer,length,0);
	if (ret == -1) {
		qDebug("connection lost, reconn");
		connected = false;
		return true;
	}
	if (ret != (int)length) {
		qDebug() << QString("send of %1 was partial %2 %3").arg(msg).arg(ret).arg(length);
		return true;
	}
	return false;
}
void wpa_client::run() {
	char buffer[1024];
	int size;
	while (1) {
		size = recv(fd,buffer,1024,0);
		buffer[size] = 0;
		pinger->start(10000);
		QString line = buffer;
		if (line == "PONG\n") {
		} else {
			qDebug() << QTime::currentTime() << QString(buffer);
		}
	}
}
something i wrote to handle it ~10 years ago



an example session:

Code: Select all

root@pi400:~# wpa_cli -i wlan0
> status
ssid=TP-LINK_Extender_5GHz
> scan
OK
<3>CTRL-EVENT-SCAN-STARTED
<3>CTRL-EVENT-SCAN-RESULTS 
> 
there is a delay between started and results, which tells you when you can then issue scan_results

the syscalls behind it:

Code: Select all

root@pi400:~# strace wpa_cli -i wlan0
socket(AF_UNIX, SOCK_DGRAM, 0)          = 3
bind(3, {sa_family=AF_UNIX, sun_path="/tmp/wpa_ctrl_14804-1"}, 110) = 0
connect(3, {sa_family=AF_UNIX, sun_path="/var/run/wpa_supplicant/wlan0"}, 110) = 0
socket(AF_UNIX, SOCK_DGRAM, 0)          = 4
bind(4, {sa_family=AF_UNIX, sun_path="/tmp/wpa_ctrl_14804-2"}, 110) = 0
connect(4, {sa_family=AF_UNIX, sun_path="/var/run/wpa_supplicant/wlan0"}, 110) = 0
send(4, "ATTACH", 6, 0)                 = 6
recv(4, "OK\n", 10, 0)                  = 3
send(3, "STATUS", 6, 0)                 = 6
recv(3, "bssid=d8:0d:xx\nfreq=518"..., 4095, 0) = 299
wpa_cli is almost exactly the same protocol send over the unix socket

dsyleixa123
Posts: 1482
Joined: Mon Jun 11, 2018 11:22 am

Re: C++ code to retrieve and set IPs a/o SSIDs in the local home network?

Sun May 09, 2021 5:24 pm

thanks cleverca22, I don't understand how to use the functions (and I'm afraid destroying aything on my Pi accidentally by faulty usage).
And my skills are very poor, I do not even know what wpa or socket are, I just know an IP address, and a SSID, and a password ;)

do you have compileable and executable code with a main() and demonstating either usage?
Last edited by dsyleixa123 on Sun May 09, 2021 5:26 pm, edited 1 time in total.

cleverca22
Posts: 3801
Joined: Sat Aug 18, 2012 2:33 pm

Re: C++ code to retrieve and set IPs a/o SSIDs in the local home network?

Sun May 09, 2021 5:26 pm

dsyleixa123 wrote:
Sun May 09, 2021 5:24 pm
thanks cleverca22, I don't understand how to use the functions (and I'm afraid destroying aything on my Pi accidentally by faulty usage).
And my skills are very poor, I do not even know what wpa or socket are, I just know an IP address, and a SSID, and a password ;)
you cant really destroy things when using wpa and sockets

also, the code i quoted, was originally written for an x86 laptop, so you dont even need to involve the pi when testing it, if you have a normal linux machine

dsyleixa123
Posts: 1482
Joined: Mon Jun 11, 2018 11:22 am

Re: C++ code to retrieve and set IPs a/o SSIDs in the local home network?

Sun May 09, 2021 5:27 pm

no, I just have a Pi 2 and no other Linux machine, and need it just for my Pi
(cross-over post:)

do you have compileable and executable code with a main() and demonstrating either usage? (I compile by Geany for the first steps, no GUI, no qt libs, just C and std:: libs and LXterminal)

cleverca22
Posts: 3801
Joined: Sat Aug 18, 2012 2:33 pm

Re: C++ code to retrieve and set IPs a/o SSIDs in the local home network?

Sun May 09, 2021 5:55 pm

stripped out all of the QT code, and now i just have:

Code: Select all

#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <stdio.h>

static inline ssize_t out(int fd, const char *msg) {
  return send(fd, msg, strlen(msg), 0);
}

int main(int argc, char **argv) {
  int fd = socket(AF_UNIX, SOCK_DGRAM, 0);
  struct sockaddr_un self;
  self.sun_family = AF_FILE;
  strncpy(self.sun_path,"/tmp/wpa_client",100);
  unlink("/tmp/wpa_client");
  bind(fd, (sockaddr*)&self,sizeof(self));
  struct sockaddr_un target;
  target.sun_family = AF_FILE;
  strncpy(target.sun_path, "/var/run/wpa_supplicant/wlan0", 100);
  connect(fd, (sockaddr*)&target,sizeof(target));
  out(fd, "ATTACH");

  char buffer[1024];
  int size;
  bool exit_soon = false;
  while (true) {
    size = recv(fd, buffer, 1024, 0);
    buffer[size] = 0;
    printf("received: %s\n", buffer);
    if (exit_soon) {
      out(fd, "DETACH");
      break;
    }
    if (strcmp(buffer,"OK\n") == 0) {
      out(fd, "STATUS");
      out(fd, "SCAN");
    } else if (strcmp(buffer, "<3>CTRL-EVENT-SCAN-RESULTS ") == 0) {
      out(fd, "SCAN_RESULTS");
     exit_soon = true;
    }
  }
}
and it does this when ran:

Code: Select all

pi@pi400:~ $ g++ wifi-test.cpp -o wifi-test && ./wifi-test
received: OK

received: bssid=d8:0d:17:xxx
freq=5180
ssid=TP-LINK_Extender_5GHz
id=0
mode=station
pairwise_cipher=CCMP
group_cipher=TKIP
key_mgmt=WPA2-PSK
wpa_state=COMPLETED
ip_address=192.168.2.56
p2p_device_address=42:8e:25:xxx
address=dc:a6:32:xxx
ieee80211ac=1

received: OK

received: <3>CTRL-EVENT-SCAN-STARTED
received: bssid=d8:0d:17:xxx
freq=5180
ssid=TP-LINK_Extender_5GHz
id=0
mode=station
pairwise_cipher=CCMP
group_cipher=TKIP
key_mgmt=WPA2-PSK
wpa_state=COMPLETED
ip_address=192.168.2.56
p2p_device_address=42:8e:25:xxx
address=dc:a6:32:xxx
ieee80211ac=1

received: FAIL-BUSY

received: <3>CTRL-EVENT-BSS-ADDED 49 f8:ab:05:xxx
received: <3>CTRL-EVENT-SCAN-RESULTS
received: bssid / frequency / signal level / flags / ssid
d8:0d:17:xxx       5180    -41     [WPA-PSK-CCMP+TKIP][WPA2-PSK-CCMP+TKIP][WPS][ESS]       TP-LINK_Extender_5GHz
d8:0d:17:xxx       2457    -76     [WPA-PSK-CCMP+TKIP][WPA2-PSK-CCMP+TKIP][WPS][ESS]       TP-LINK_Extender_2.4GHz

pi@pi400:~ $
after the initial connection, it sends ATTACH, and the server responds with OK
it then sends STATUS and SCAN
the server responds immediately with the current status, and then a short while later with SCAN-RESULTS
so it fires off a scan_results command to query it all, and then exits

all thats missing, is code to parse the reply out of a char* and give you want you need

dsyleixa123
Posts: 1482
Joined: Mon Jun 11, 2018 11:22 am

Re: C++ code to retrieve and set IPs a/o SSIDs in the local home network?

Sun May 09, 2021 6:24 pm

thank you, it compiles and runs, printing lots of things, not sure how to get the abitrary infos I want to store though, tbh...

dsyleixa123
Posts: 1482
Joined: Mon Jun 11, 2018 11:22 am

Re: C++ code to retrieve and set IPs a/o SSIDs in the local home network?

Mon May 10, 2021 12:02 pm

hmmm, I don't get it, it prints things out, but where are they stored?
And which are the single lines to retrieve and store values from that, e.g.
string wifi_localIP: detect e.g. "192.168.2.108"
string wifi_SSID: detect e.g. "WLAN-1234567890"
string wifi_gatewayIP: detect e.g. "192.168.2.1"
int wifi_RSSI: detect e.g. 70 //(0...100)

and how to get the list of all available WiFi networks to choose one from for a re-connection?
how would one program that list by an array of strings, probably dynamically?

(as stated, I want these data for further processing in my program, not just a print-out)

dsyleixa123
Posts: 1482
Joined: Mon Jun 11, 2018 11:22 am

Re: C++ code to retrieve and set IPs a/o SSIDs in the local home network?

Tue May 11, 2021 5:47 pm

any hints by anyone? I don't see how to retrieve and store the required WiFi values in (local arbitrary) program variables

cleverca22
Posts: 3801
Joined: Sat Aug 18, 2012 2:33 pm

Re: C++ code to retrieve and set IPs a/o SSIDs in the local home network?

Tue May 11, 2021 6:07 pm

dsyleixa123 wrote:
Tue May 11, 2021 5:47 pm
any hints by anyone? I don't see how to retrieve and store the required WiFi values in (local arbitrary) program variables
that gets into the subject of parsing a string into multiple pieces, which ive not done very much of

youll need to look into things like scanf or flex/bison i'm guessing

dsyleixa123
Posts: 1482
Joined: Mon Jun 11, 2018 11:22 am

Re: C++ code to retrieve and set IPs a/o SSIDs in the local home network?

Tue May 11, 2021 7:06 pm

yes, ok, but where is the entire string of all and everything to parse? I don't see a
string wifi_allandeverything; :?

cleverca22
Posts: 3801
Joined: Sat Aug 18, 2012 2:33 pm

Re: C++ code to retrieve and set IPs a/o SSIDs in the local home network?

Tue May 11, 2021 7:12 pm

dsyleixa123 wrote:
Tue May 11, 2021 7:06 pm
yes, ok, but where is the entire string of all and everything to parse? I don't see a
string wifi_allandeverything; :?
printf("received: %s\n", buffer);

Code: Select all

received: bssid=d8:0d:17:xxx
freq=5180
ssid=TP-LINK_Extender_5GHz
id=0
mode=station
pairwise_cipher=CCMP
group_cipher=TKIP
key_mgmt=WPA2-PSK
wpa_state=COMPLETED
ip_address=192.168.2.56
p2p_device_address=42:8e:25:xxx
address=dc:a6:32:xxx
ieee80211ac=1
in one of the passes of the loop, the buffer string contains all of this

dsyleixa123
Posts: 1482
Joined: Mon Jun 11, 2018 11:22 am

Re: C++ code to retrieve and set IPs a/o SSIDs in the local home network?

Tue May 11, 2021 7:15 pm

mhmmm, and what is the function out() for? I assumed this was it which does the print out (admittedly I don't understand anything of all that nested and obfuscated code... ;-) )

PS,
and there are just 2 things I can identify:
ssid=TP-LINK_Extender_5GHz
ip_address=192.168.2.56

where is the IP of the router,
where is/are the RSSI,
and where are all the rest of all optional available networks (routers? gateways? access points?)
ssidNum= n(?)
ssid[1]= ? RSSI[1]=?
ssid[2]= ? RSSI[2]=?
ssid[3]= ? RSSI[3]=?
ssid[4]= ? RSSI[4]=?
...
ssid[n]= ? RSSI[n]=?
(so that I can sort the ssids by their RRSis)

User avatar
DougieLawson
Posts: 41316
Joined: Sun Jun 16, 2013 11:19 pm
Location: A small cave in deepest darkest Basingstoke, UK
Contact: Website Twitter

Re: C++ code to retrieve and set IPs a/o SSIDs in the local home network?

Tue May 11, 2021 7:37 pm

cleverca22 wrote:
Tue May 11, 2021 6:07 pm
that gets into the subject of parsing a string into multiple pieces, which I've not done very much of ...
For most bang for your buck have a look at Perl compatible regular expressions (PCRE). If you can get the regex right the parsing becomes trivial.

I've had loads of fun playing with those pieces.

This is a rather crude example

Code: Select all

#include <pcre.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main (int arcg, char* argv[])
{
        pcre *regComp;
        pcre_extra *pcreExtra;
        int pcreExecRet;
        int subStrVec[30];
        const char* pcreErrorStr;
        int pcreErrorOffset;
        char* aStrRegex;
        char** aLineToMatch;
        const char* psubStrMatchStr;
        int j;
        char* testString[] = {
                "HTTP/1.1 401 Unauthorized (ASN:s6.myenergi.net) (SN:10008888)\r\n",
                "server: cloudflare\r\n",
                "X_MYENERGI-asn: s6.myenergi.net\r\n",
                NULL};
        aStrRegex = "x_myenergi-asn: (.*.myenergi.net)";
        regComp = pcre_compile(aStrRegex, PCRE_CASELESS, &pcreErrorStr, &pcreErrorOffset, NULL);
        if (regComp == NULL)
        {
                printf("Error: %s %s\n", aStrRegex, pcreErrorStr);
                exit(1);
        }
        pcreExtra = pcre_study(regComp, 0, &pcreErrorStr);
        if (pcreErrorStr != NULL)
        {
                printf("Study: %s %s\n", aStrRegex, pcreErrorStr);
                exit(1);
        }
        for (aLineToMatch=testString; *aLineToMatch != NULL; aLineToMatch++)
        {
                printf("String: %s\n", *aLineToMatch);
                printf("        ----+----1----+----2----+----3----+----4----+----5\n");
                pcreExecRet = pcre_exec(regComp, pcreExtra, *aLineToMatch,
                        strlen(*aLineToMatch), 0, 0, subStrVec, 30);
                if (pcreExecRet > 0)
                {
                        printf("Matched\n");
                        for (j=0; j<pcreExecRet; j++)
                        {
                                pcre_get_substring(*aLineToMatch, subStrVec, pcreExecRet, j, &(psubStrMatchStr));
                                printf("Match (%2d/%2d): (%2d, %2d): %s\n", j, pcreExecRet-1, subStrVec[j*2],
                                               subStrVec[j*2+1], psubStrMatchStr);
                        }
                }
                else if (pcreExecRet < 0)
                {
                        switch(pcreExecRet)
                        {
                                case PCRE_ERROR_NOMATCH : printf("No match\n"); break;
                                case PCRE_ERROR_NULL : printf("Null\n"); break;
                                case PCRE_ERROR_BADOPTION : printf("Bad opt\n"); break;
                                case PCRE_ERROR_BADMAGIC : printf("Voodoo\n"); break;
                                case PCRE_ERROR_UNKNOWN_NODE : printf("Something kooky\n"); break;
                                case PCRE_ERROR_NOMEMORY : printf("Oom\n"); break;
                                default : printf("Very bad\n"); break;
                        }
                }
                else
                {
                        printf("No error, but no match");
                }
                printf("\n");
        }
        pcre_free(regComp);
        if (pcreExtra != NULL)
        {
#ifdef PCRE_CONFIG_JIT
                pcre_free_study(pcreExtra);
#else
                pcre_free(pcreExtra);
#endif
        }
        return 0;
}
I'm looking for a string in the headers returned from a website (for my car charger).

Here's a redacted sample of the full set if headers that come back.

Code: Select all

HTTP/1.1 401 Unauthorized
Date: Sun, 09 May 2021 19:07:59 GMT
Transfer-Encoding: chunked
Connection: keep-alive
Set-Cookie: __cfduid=<redacted>; expires=Tue, 08-Jun-21 19:07:58 GMT; path=/; domain=.myenergi.net; HttpOnly; SameSite=Lax
WWW-Authenticate: Digest realm="MyEnergi Telemetry",qop="auth",nonce="<redacted>",opaque="000000100000000100000000f72ea42300007b69b27acf1fc135f0f4cf9bdf3f93460e8f72bd797786e87676196d728f",Stale="false",algorithm="MD5"
CF-Cache-Status: DYNAMIC
cf-request-id: 09f4208a2c0000dc37aa8c9000000001
Report-To: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report?s=<redacted>"}],"group":"cf-nel","max_age":604800}
NEL: {"report_to":"cf-nel","max_age":604800}
Server: cloudflare
CF-RAY: 64cd36bd1e42dc37-LHR
alt-svc: h3-27=":443"; ma=86400, h3-28=":443"; ma=86400, h3-29=":443"; ma=86400

HTTP/1.1 401 Unauthorized (ASN:s6.myenergi.net) (SN:redacted)
Date: Sun, 09 May 2021 19:07:59 GMT
Transfer-Encoding: chunked
Connection: keep-alive
Set-Cookie: __cfduid=<redacted>; expires=Tue, 08-Jun-21 19:07:59 GMT; path=/; domain=.myenergi.net; HttpOnly; SameSite=Lax
X_MYENERGI-asn: s6.myenergi.net
WWW-Authenticate: Digest realm="MyEnergi Telemetry",qop="auth",nonce="<redcated>",opaque="000000100000000100000000f72ea42300007b69b27acf1fc135f0f4cf9bdf3f93460e8f72bd797786e87676196d728f",Stale="false",algorithm="MD5"
CF-Cache-Status: DYNAMIC
cf-request-id: 09f4208ac10000dc37008f2000000001
Report-To: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report?s=<redacted>"}],"group":"cf-nel","max_age":604800}
NEL: {"report_to":"cf-nel","max_age":604800}
Server: cloudflare
CF-RAY: 64cd36be0fbddc37-LHR
alt-svc: h3-27=":443"; ma=86400, h3-28=":443"; ma=86400, h3-29=":443"; ma=86400
Any language using left-hand whitespace for syntax is ridiculous

Any DMs sent on Twitter will be answered next month.
Fake doctors - are all on my foes list.

Any requirement to use a crystal ball or mind reading will result in me ignoring your question.

cleverca22
Posts: 3801
Joined: Sat Aug 18, 2012 2:33 pm

Re: C++ code to retrieve and set IPs a/o SSIDs in the local home network?

Tue May 11, 2021 7:38 pm

dsyleixa123 wrote:
Tue May 11, 2021 7:15 pm
mhmmm, and what is the function out() for? I assumed this was it which does the print out (admittedly I don't understand anything of all that nested and obfuscated code... )
the send() function needs the length of a the thing to send
writing send(fd,"foo",strlen("foo")); makes the code messy, and opens you to mistakes
so i made a function to handle that for me
dsyleixa123 wrote:
Tue May 11, 2021 7:15 pm
PS,
and there are just 2 things I can identify:
ssid=TP-LINK_Extender_5GHz
ip_address=192.168.2.56

where is the IP of the router,
where is/are the RSSI,
thats the ssid i'm currently connected to, and the ip of my pi400
dsyleixa123 wrote:
Tue May 11, 2021 7:15 pm
and where are all the rest of all optional available networks (routers? gateways? access points?)
thats further down in the example i pasted:

Code: Select all

received: <3>CTRL-EVENT-SCAN-RESULTS
received: bssid / frequency / signal level / flags / ssid
d8:0d:17:xxx       5180    -41     [WPA-PSK-CCMP+TKIP][WPA2-PSK-CCMP+TKIP][WPS][ESS]       TP-LINK_Extender_5GHz
d8:0d:17:xxx       2457    -76     [WPA-PSK-CCMP+TKIP][WPA2-PSK-CCMP+TKIP][WPS][ESS]       TP-LINK_Extender_2.4GHz

dsyleixa123
Posts: 1482
Joined: Mon Jun 11, 2018 11:22 am

Re: C++ code to retrieve and set IPs a/o SSIDs in the local home network?

Tue May 11, 2021 7:55 pm

aha, I slowly see... but then I still have no idea how to extract all the details and store them to my arbitrary program variables, tbh.
I'm afraid I have to give up, too much awkward code and stuff... (In Arduino API I have WiFi (Wifi101, esp WiFi) classes for all that)

swampdog
Posts: 698
Joined: Fri Dec 04, 2015 11:22 am

Re: C++ code to retrieve and set IPs a/o SSIDs in the local home network?

Wed May 12, 2021 10:29 am

I think you may have reached the stage where lack of generic tools is holding you back.

This little snippet I plugged into my basic app structure..

Code: Select all

static sdRet
avBar(sdArg1 ds,sdArg2 so)
{const sdSiz    dsn     (sdArgs::ArgIdx(ds,so));

 if (!sdSizeOk(ds,dsn))
        throw sde_App("[wlan0]")
 ;

 sdConStr       csi,
                cso;

 csi.push_back("sudo iwlist "+ds[dsn]+" scan");
// sdScript(csi,&cso,true);
sdFileLoad(&cso,"/wrk/zz");

 sdStanza       stz     (cso,"[[:space:]]Cell[[:space:]]");
 sdSiz          b,e;

 while (stz.Next(&b,&e))        {
        sdConStr        cs;
        sdVar           v;

        csi.clear();
        std::copy(
                cso.begin()+b,cso.begin()+e,
                std::back_inserter(csi)
                )
        ;

        sdStrTok(&cs,csi[0],sdSpc());
        v["Cell"] = cs[1];
        v["Mac"] = cs[4];

        cs.clear();
        sdStrTok(&cs,csi[5],":");
        v["ESSID"] = cs[1];
v.Dump();sdLog()<<'\n';
 }
 return sdMaxSiz();
}
..which is, if you've got well tested stuff to call upon, demonstrating it is possible to slap code together and concentrate on the problem in hand. The output from the above..

Code: Select all


foo@pi20:~/usr/src/junk $ ./go run --bar wlan0
[0]Cell=01
[1]ESSID="ook!"
[2]Mac=E8:DE:27:E9:83:EA

[0]Cell=02
[1]ESSID="eek"
[2]Mac=C8:3A:35:F4:97:40

[0]Cell=03
[1]ESSID="HP-Print-89-LaserJet 200 color"
[2]Mac=48:5A:B6:6A:DD:89

[0]Cell=04
[1]ESSID="VM7506420"
[2]Mac=E4:57:40:44:88:5C

[0]Cell=05
[1]ESSID="sdtab"
[2]Mac=B8:27:EB:2E:17:90

[0]Cell=06
[1]ESSID="VM7506420"
[2]Mac=E4:57:40:44:88:5D

Note I soon got bored of running sdScript() so dumped it's output (sudo iwlist wlan0 scan >/wrk/zz) and worked with /wrk/zz from there. Also stops the output changing and we can go back later to cater for "iwlist" not always returning what we want.

  • sdScript(csi,&cso,true) creates an on-the-fly script and in this case redirects stdout/stderr to a tempfile which it then loads into 'cso'. sdConStr is a container of strings (eg: deque<string>).

    sdStanza uses a regex to split the output into chunks, in this case the line with "Cell" in it. We can come back to that regex later and write it properly.

    the while loop gets indices of where each stanza starts/ends, basically each one starts with "Cell" and contains all the junk up to the next "Cell" or "eof". We reuse 'csi' because we don't need its contents any more.

    sdStrTok(&out,inp,tok) splits string 'inp' into an array 'out' using 'tok' as the delimiter. We need to come back to this because we're using fixed indices and it will crash at some point. Should have used sdRegex but the meaning this way is clearer.

    sdVar is map<string,string> which is likely obvious to others because the output isn't in the same order in which I set the variables. v.Dump() is a -DDEBUG only method but suffices here.

    the function declaration itself can be ignored. It's a callback function for sdArgs (argc/argv processor).

You don't have to write it all yourself like I did but it is educational. :-)

Return to “C/C++”