Quellcode durchsuchen

Erste Sicherung

Rind vor 7 Jahren
Commit
21205c3981

+ 13 - 0
.gitignore

@@ -0,0 +1,13 @@
+# git ls-files --others --exclude-from=.git/info/exclude
+# Lines that start with '#' are comments.
+# For a project mostly in C, the following would be a good set of
+# exclude patterns (uncomment them if you want to use them):
+# *.[oa]
+# *~
+
+test/
+res/
+*.ncb
+*.o
+*.user
+Visual Studio 2008/

+ 11 - 0
libgfanet/.gitignore

@@ -0,0 +1,11 @@
+# git ls-files --others --exclude-from=.git/info/exclude
+# Lines that start with '#' are comments.
+# For a project mostly in C, the following would be a good set of
+# exclude patterns (uncomment them if you want to use them):
+# *.[oa]
+# *~
+
+Debug/
+Release/
+res/
+*.user

+ 71 - 0
libgfanet/gfanet.cpp

@@ -0,0 +1,71 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <regex>
+#include <string>
+#include <sstream>
+#include <iostream>
+#include "util.h"
+#include "gfanet.h"
+
+/////////////////////////////////////////////////////////////////////////////
+
+#define _PROC_NET_DEV					"/proc/net/dev"
+
+/////////////////////////////////////////////////////////////////////////////
+
+int GetAvailableInterfaces(NETINTERFACE_LIST &nil)
+{
+	static const std::string strRegExLine = "^\\s*([^:]+):\\s*([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)$";
+	static std::regex regl(strRegExLine, std::regex_constants::ECMAScript | std::regex_constants::optimize);
+	std::string buf;
+	int nCntItf = 0;
+
+	if(ReadFile(_PROC_NET_DEV, buf) > 0)
+	{
+		std::string line;
+		std::istringstream iss(buf);
+		std::istream stm(iss.rdbuf());
+
+		while(std::getline(stm, line))
+		{
+			std::smatch resl;
+
+			if(	line.size() > 0 &&
+				regex_search(line, resl, regl))
+			{
+				if(resl.size() == 18)
+				{
+					NETINTERFACE ni;
+					memset(&ni, 0, sizeof(ni));
+
+					resl[1].str().copy(ni.name, sizeof(ni.name) - 1);
+					ni.stats.rx_bytes			= std::stoul(resl[2].str());
+					ni.stats.rx_packets			= std::stoul(resl[3].str());
+					ni.stats.rx_errors			= std::stoul(resl[4].str());
+					ni.stats.rx_dropped			= std::stoul(resl[5].str());
+					ni.stats.rx_fifo_errors		= std::stoul(resl[6].str());
+					ni.stats.rx_frame_errors	= std::stoul(resl[7].str());
+					ni.stats.rx_compressed		= std::stoul(resl[8].str());
+					ni.stats.rx_multicast		= std::stoul(resl[9].str());
+					ni.stats.tx_bytes			= std::stoul(resl[10].str());
+					ni.stats.tx_packets			= std::stoul(resl[11].str());
+					ni.stats.tx_errors			= std::stoul(resl[12].str());
+					ni.stats.tx_dropped			= std::stoul(resl[13].str());
+					ni.stats.tx_fifo_errors		= std::stoul(resl[14].str());
+					ni.stats.tx_collisions		= std::stoul(resl[15].str());
+					ni.stats.tx_carrier_errors	= std::stoul(resl[16].str());
+					ni.stats.tx_compressed		= std::stoul(resl[17].str());
+					nil.push_back(ni);
+					nCntItf++;
+				}
+			}
+		}
+	}
+
+	return nCntItf;
+}

+ 69 - 0
libgfanet/gfanet.h

@@ -0,0 +1,69 @@
+// gfanet.h :
+//
+
+#if !defined(AGD_GFANET_H__295C6C24_8700_40C8_B8BE_806C2D11FD0D__INCLUDED_)
+#define AGD_GFANET_H__295C6C24_8700_40C8_B8BE_806C2D11FD0D__INCLUDED_
+
+#include <string>
+#include <vector>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <linux/if_packet.h>
+#include <linux/if_arp.h>
+#include "interfaces.h"
+
+/////////////////////////////////////////////////////////////////////////////
+// gfanet.h - Declarations:
+
+typedef struct _NETINTERFACE_STATS
+{
+	unsigned long rx_bytes;
+	unsigned long rx_packets;
+	unsigned long rx_errors;
+	unsigned long rx_dropped;
+	unsigned long rx_fifo_errors;
+	unsigned long rx_frame_errors;
+	unsigned long rx_compressed;
+	unsigned long rx_multicast;
+	unsigned long tx_bytes;
+	unsigned long tx_packets;
+	unsigned long tx_errors;
+	unsigned long tx_dropped;
+	unsigned long tx_fifo_errors;
+	unsigned long tx_collisions;
+	unsigned long tx_carrier_errors;
+	unsigned long tx_compressed;
+}NETINTERFACE_STATS, *LPNETINTERFACE_STATS;
+typedef const NETINTERFACE_STATS *LPCNETINTERFACE_STATS;
+
+typedef struct _NETINTERFACE
+{
+	char name[IFNAMSIZ];
+	NETINTERFACE_STATS stats;
+}NETINTERFACE, *LPNETINTERFACE;
+typedef const NETINTERFACE *LPCNETINTERFACE;
+typedef std::vector<NETINTERFACE> NETINTERFACE_LIST;
+
+/////////////////////////////////////////////////////////////////////////////
+
+typedef struct _ETC_NW_ITF_LINE
+{
+	std::vector<std::string> vals;
+}ETC_NW_ITF_LINE, *LPETC_NW_ITF_LINE;
+typedef const ETC_NW_ITF_LINE *LPCETC_NW_ITF_LINE;
+
+typedef struct _ETC_NW_ITF
+{
+	std::vector<ETC_NW_ITF_LINE> lines;
+}ETC_NW_ITF, *LPETC_NW_ITF;
+typedef const ETC_NW_ITF *LPCETC_NW_ITF;
+typedef std::vector<ETC_NW_ITF> ETC_NW_ITF_LIST;
+
+/////////////////////////////////////////////////////////////////////////////
+
+int GetAvailableInterfaces(NETINTERFACE_LIST &nil);
+
+/////////////////////////////////////////////////////////////////////////////
+#endif	//	!defined(AGD_GFANET_H__295C6C24_8700_40C8_B8BE_806C2D11FD0D__INCLUDED_)

+ 36 - 0
libgfanet/gfanet.pro

@@ -0,0 +1,36 @@
+TEMPLATE = lib
+TARGET = gfanet
+CONFIG += plugin c++11
+
+#TARGET = $$qtLibraryTarget($$TARGET)
+
+CONFIG(debug, debug|release) {
+    QMAKE_CXXFLAGS -= -Os
+    QMAKE_CFLAGS -= -Os
+    QMAKE_CXXFLAGS += -D_DEBUG
+    QMAKE_CFLAGS += -D_DEBUG
+}
+
+# Input
+SOURCES += \
+    gfanet.cpp \
+    util.cpp \
+    interfaces.cpp \
+    inet4s.cpp \
+    inet4d.cpp \
+    inet4m.cpp
+
+HEADERS += \
+    gfanet.h \
+    util.h \
+    interfaces.h \
+    inet4s.h \
+    inet4d.h \
+    inet4m.h
+
+#unix {
+#    installPath = $$[QT_INSTALL_QML]/$$replace(uri, \\., /)
+#    qmldir.path = $$installPath
+#    target.path = $$installPath
+#    INSTALLS += target qmldir
+#}

+ 93 - 0
libgfanet/inet4d.cpp

@@ -0,0 +1,93 @@
+#include "util.h"
+#include "inet4d.h"
+
+/////////////////////////////////////////////////////////////////////////////
+
+bool ParseIfaceInet4dParam(const std::vector<std::string> &v, IFACE_INET_DHCP &id)
+{
+	auto vSize = v.size();
+
+	if(vSize >= 2)
+	{
+		if(!v[0].compare("hostname"))
+		{
+			id.hostname = v[1];
+			return true;
+		}
+		else if(!v[0].compare("metric") && IsDecimalInt(v[1].c_str()))
+		{
+			id.metric = (int)std::stol(v[1], 0, 0);
+			return true;
+		}
+		else if(!v[0].compare("leasehours") && IsDecimalInt(v[1].c_str()))
+		{
+			id.leasehours = (int)std::stol(v[1], 0, 0);
+			return true;
+		}
+		else if(!v[0].compare("leasetime") && IsDecimalInt(v[1].c_str()))
+		{
+			id.leasetime = (int)std::stol(v[1], 0, 0);
+			return true;
+		}
+		else if(!v[0].compare("vendor"))
+		{
+			id.vendor = v[1];
+			return true;
+		}
+		else if(!v[0].compare("client"))
+		{
+			id.client = v[1];
+			return true;
+		}
+		else if(!v[0].compare("hwaddress"))
+		{
+			id.hwaddr = v[1];
+			strlcase(id.hwaddr);
+			return true;
+		}
+	}
+
+	return false;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+bool WriteIfaceInet4dParam(FILE *pf, const IFACE_INET_DHCP &id)
+{
+	if(!id.hostname.empty())
+	{
+		fprintf(pf, "\thostname %s\n", id.hostname.c_str());
+	}
+
+	if(id.metric >= 0)
+	{
+		fprintf(pf, "\tmetric %d\n", id.metric);
+	}
+
+	if(id.leasehours > 0)
+	{
+		fprintf(pf, "\tleasehours %d\n", id.leasehours);
+	}
+
+	if(id.leasetime > 0)
+	{
+		fprintf(pf, "\tleasetime %d\n", id.leasetime);
+	}
+
+	if(!id.vendor.empty())
+	{
+		fprintf(pf, "\tvendor %s\n", id.vendor.c_str());
+	}
+
+	if(!id.client.empty())
+	{
+		fprintf(pf, "\tclient %s\n", id.client.c_str());
+	}
+
+	if(!id.hwaddr.empty())
+	{
+		fprintf(pf, "\thwaddress %s\n", id.hwaddr.c_str());
+	}
+
+	return true;
+}

+ 47 - 0
libgfanet/inet4d.h

@@ -0,0 +1,47 @@
+// inet4d.h : iface ... inet dhcp
+//
+
+#if !defined(AGD_INET4D_H__73CD3DB6_DC51_4C36_946A_B12C1126D875__INCLUDED_)
+#define AGD_INET4D_H__73CD3DB6_DC51_4C36_946A_B12C1126D875__INCLUDED_
+
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <linux/if_packet.h>
+#include <linux/if_arp.h>
+#include <vector>
+#include <string>
+
+/////////////////////////////////////////////////////////////////////////////
+// inet4d.h - Declarations:
+
+typedef struct _IFACE_INET_DHCP
+{
+	_IFACE_INET_DHCP(){_reset();}
+	void _reset(void)
+	{
+		metric = -1;
+		leasehours = -1;
+		leasetime = -1;
+		hostname.clear();
+		vendor.clear();
+		client.clear();
+		hwaddr.clear();
+	}
+	std::string hostname;	// Hostname to be requested
+	int metric;
+	int leasehours;			// Preferred lease time in hours
+	int leasetime;			// Preferred lease time in seconds
+	std::string vendor;		// Vendor class identifier (dhcpcd)
+	std::string client;		// Client identifier (dhcpcd)
+	std::string hwaddr;
+}IFACE_INET_DHCP, *LPIFACE_INET_DHCP;
+typedef const IFACE_INET_DHCP *LPCIFACE_INET_DHCP;
+
+bool ParseIfaceInet4dParam(const std::vector<std::string> &v, IFACE_INET_DHCP &id);
+bool WriteIfaceInet4dParam(FILE *pf, const IFACE_INET_DHCP &id);
+
+/////////////////////////////////////////////////////////////////////////////
+#endif	//	!defined(AGD_INET4D_H__73CD3DB6_DC51_4C36_946A_B12C1126D875__INCLUDED_)

+ 41 - 0
libgfanet/inet4m.cpp

@@ -0,0 +1,41 @@
+#include "util.h"
+#include "inet4m.h"
+
+/////////////////////////////////////////////////////////////////////////////
+
+bool ParseIfaceInet4mParam(const std::vector<std::string> &v, IFACE_INET_MANUAL &im)
+{
+	auto vSize = v.size();
+
+	if(vSize >= 2)
+	{
+		if(!v[0].compare("hwaddress"))
+		{
+			im.hwaddr = v[1];
+			strlcase(im.hwaddr);
+			return true;
+		}
+		else if(!v[0].compare("mtu") && IsDecimalInt(v[1].c_str()))
+		{
+			im.mtu = (int)std::stol(v[1], 0, 0);
+			return true;
+		}
+	}
+
+	return false;
+}
+
+bool WriteIfaceInet4mParam(FILE *pf, const IFACE_INET_MANUAL &im)
+{
+	if(!im.hwaddr.empty())
+	{
+		fprintf(pf, "\thwaddress %s\n", im.hwaddr.c_str());
+	}
+
+	if(im.mtu >= 0)
+	{
+		fprintf(pf, "\tmtu %d\n", im.mtu);
+	}
+
+	return true;
+}

+ 27 - 0
libgfanet/inet4m.h

@@ -0,0 +1,27 @@
+// inet4m.h : iface ... inet manual
+//
+
+#if !defined(AGD_INET4M_H__2CA1785D_5775_461B_8C59_FCFE6C5395CE__INCLUDED_)
+#define AGD_INET4M_H__2CA1785D_5775_461B_8C59_FCFE6C5395CE__INCLUDED_
+
+/////////////////////////////////////////////////////////////////////////////
+// inet4m.h - Declarations:
+
+typedef struct _IFACE_INET_MANUAL
+{
+	_IFACE_INET_MANUAL(){_reset();}
+	void _reset(void)
+	{
+		mtu = -1;
+		hwaddr.clear();
+	}
+	int mtu;
+	std::string hwaddr;
+}IFACE_INET_MANUAL, *LPIFACE_INET_MANUAL;
+typedef const IFACE_INET_MANUAL *LPCIFACE_INET_MANUAL;
+
+bool ParseIfaceInet4mParam(const std::vector<std::string> &v, IFACE_INET_MANUAL &im);
+bool WriteIfaceInet4mParam(FILE *pf, const IFACE_INET_MANUAL &im);
+
+/////////////////////////////////////////////////////////////////////////////
+#endif	//	!defined(AGD_INET4M_H__2CA1785D_5775_461B_8C59_FCFE6C5395CE__INCLUDED_)

+ 224 - 0
libgfanet/inet4s.cpp

@@ -0,0 +1,224 @@
+#include "util.h"
+#include "inet4s.h"
+
+/////////////////////////////////////////////////////////////////////////////
+
+bool ParseIfaceInet4sParam(const std::vector<std::string> &v, IFACE_INET_STATIC &is)
+{
+	auto vSize = v.size();
+
+	if(vSize >= 2)
+	{
+		struct in_addr addr, mask;
+		if(!v[0].compare("address"))
+		{
+			std::vector<std::string> va;
+			SplitString(v[1], "[^\\/]+", va);
+
+			if(va.size() == 1)
+			{
+				if(inet_aton(va[0].c_str(), &addr))
+				{
+					is.addr = addr;
+					return true;
+				}
+			}
+			else if(va.size() == 2)
+			{
+				if(inet_aton(va[0].c_str(), &addr))
+				{
+					if(IsDecimalInt(va[1].c_str()))
+					{
+						unsigned int nBits = (unsigned int)std::stoul(va[1], 0, 0);
+						if(nBits <= 32)
+							is.netprefix = nBits;
+					}
+					else if(inet_aton(va[1].c_str(), &mask) && IsValidNetmask(mask))
+						is.netprefix = Mask2Prefix(mask);
+					else
+						return false;
+					is.addr = addr;
+					return true;
+				}
+			}
+		}
+		else if(!v[0].compare("gateway"))
+		{
+			if(inet_aton(v[1].c_str(), &addr))
+			{
+				is.gate = addr;
+				return true;
+			}
+		}
+		else if(!v[0].compare("broadcast"))
+		{
+			if(inet_aton(v[1].c_str(), &addr))
+			{
+				is.bcast = addr;
+				return true;
+			}
+			else if(!v[1].compare("-"))
+			{
+				is.bcastOpt = -1;
+				return true;
+			}
+		}
+		else if(!v[0].compare("pointopoint"))
+		{
+			if(inet_aton(v[1].c_str(), &addr))
+			{
+				is.pointopoint = addr;
+				return true;
+			}
+		}
+		else if(!v[0].compare("netmask"))
+		{
+			if(IsDecimalInt(v[1].c_str()))
+			{
+				unsigned int nBits = (unsigned int)std::stoul(v[1], 0, 0);
+				if(nBits <= 32)
+				{
+					is.netmask.s_addr = Prefix2Mask(nBits);
+					return true;
+				}
+			}
+			else if(inet_aton(v[1].c_str(), &mask))
+			{
+				if(IsValidNetmask(mask))
+				{
+					is.netmask = mask;
+					return true;
+				}
+			}
+		}
+		else if(!v[0].compare("dns-nameservers"))
+		{
+			int bNs = 0;
+			for(size_t i = 1, j = 0; i < vSize && j < _countof(is.namesvr); i++, j++)
+			{
+				if(inet_aton(v[i].c_str(), &addr))
+				{
+					is.namesvr[j] = addr;
+					bNs++;
+				}
+			}
+			return bNs > 0;
+		}
+		else if(!v[0].compare("dns-search"))
+		{
+			for(size_t i = 1; i < vSize; i++)
+			{
+				is.dnss.push_back(v[i]);
+			}
+			return true;
+		}
+		else if(!v[0].compare("hwaddress"))
+		{
+			is.hwaddr = v[1];
+			strlcase(is.hwaddr);
+			return true;
+		}
+		else if(!v[0].compare("metric") && IsDecimalInt(v[1].c_str()))
+		{
+			is.metric = (int)std::stol(v[1], 0, 0);
+			return true;
+		}
+		else if(!v[0].compare("mtu") && IsDecimalInt(v[1].c_str()))
+		{
+			is.mtu = (int)std::stol(v[1], 0, 0);
+			return true;
+		}
+		else if(!v[0].compare("scope"))
+		{
+			is.scope = v[1];
+			return true;
+		}
+	}
+
+	return false;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+bool WriteIfaceInet4sParam(FILE *pf, const IFACE_INET_STATIC &is)
+{
+	if(is.addr.s_addr != INADDR_ANY)
+	{
+		fprintf(pf, "\taddress %s", inet_ntoa(is.addr));
+		if(is.netprefix)
+			fprintf(pf, "/%u", is.netprefix);
+		fputc('\n', pf);
+	}
+#if 0
+	if(!is.netprefix && is.netmask.s_addr != INADDR_ANY)
+	{
+		fprintf(pf, "\tnetmask %s\n", inet_ntoa(is.netmask));
+	}
+#endif
+	if(is.gate.s_addr != INADDR_ANY)
+	{
+		fprintf(pf, "\tgateway %s\n", inet_ntoa(is.gate));
+	}
+
+	if(is.bcastOpt == -1)
+	{
+		fprintf(pf, "\tbroadcast -\n");
+	}
+	else if(is.bcast.s_addr != INADDR_ANY)
+	{
+		fprintf(pf, "\tbroadcast %s\n", inet_ntoa(is.bcast));
+	}
+
+	if(is.pointopoint.s_addr != INADDR_ANY)
+	{
+		fprintf(pf, "\tpointopoint %s\n", inet_ntoa(is.pointopoint));
+	}
+
+	if(is.namesvr[0].s_addr != INADDR_ANY)
+	{
+		fputs("\tdns-nameservers", pf);
+		for(size_t i = 0; i < _countof(is.namesvr); i++)
+		{
+			if(is.namesvr[i].s_addr != INADDR_ANY)
+			{
+				fputc(' ', pf);
+				fputs(inet_ntoa(is.namesvr[i]), pf);
+			}
+		}
+		fputc('\n', pf);
+	}
+
+	if(is.dnss.size() > 0)
+	{
+		fputs("\tdns-search", pf);
+		for(auto it = is.dnss.begin(); it != is.dnss.end(); it++)
+		{
+			const std::string &ds = *it;
+			fputc(' ', pf);
+			fputs(ds.c_str(), pf);
+		}
+		fputc('\n', pf);
+	}
+
+	if(!is.hwaddr.empty())
+	{
+		fprintf(pf, "\thwaddress %s\n", is.hwaddr.c_str());
+	}
+
+	if(is.metric >= 0)
+	{
+		fprintf(pf, "\tmetric %d\n", is.metric);
+	}
+
+	if(is.mtu >= 0)
+	{
+		fprintf(pf, "\tmtu %d\n", is.mtu);
+	}
+
+	if(!is.scope.empty())
+	{
+		fprintf(pf, "\tscope %s\n", is.scope.c_str());
+	}
+
+	return true;
+}

+ 59 - 0
libgfanet/inet4s.h

@@ -0,0 +1,59 @@
+// inet4s.h : iface ... inet static
+//
+
+#if !defined(AGD_INET4S_H__8DD9BEA3_89E3_42BA_88AC_9D805D2CAEBC__INCLUDED_)
+#define AGD_INET4S_H__8DD9BEA3_89E3_42BA_88AC_9D805D2CAEBC__INCLUDED_
+
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <linux/if_packet.h>
+#include <linux/if_arp.h>
+#include <vector>
+#include <string>
+
+/////////////////////////////////////////////////////////////////////////////
+// inet4s.h - Declarations:
+
+typedef struct _IFACE_INET_STATIC
+{
+	_IFACE_INET_STATIC(){_reset();}
+	void _reset(void)
+	{
+		addr.s_addr = INADDR_ANY;
+		gate.s_addr = INADDR_ANY;
+		bcast.s_addr = INADDR_ANY;
+		pointopoint.s_addr = INADDR_ANY;
+		netmask.s_addr = INADDR_ANY;
+		memset(&namesvr, 0, sizeof(namesvr));
+		netprefix = 0;
+		bcastOpt = 0;
+		metric = -1;
+		mtu = -1;
+		hwaddr.clear();
+		scope.clear();
+		dnss.clear();
+	}
+    struct in_addr addr;
+    struct in_addr netmask;
+    struct in_addr gate;
+    struct in_addr bcast;
+    struct in_addr pointopoint;
+	struct in_addr namesvr[3];
+	unsigned int netprefix;
+	int bcastOpt;
+	int metric;
+	int mtu;
+	std::string hwaddr;
+	std::string scope;
+	std::vector<std::string> dnss;
+}IFACE_INET_STATIC, *LPIFACE_INET_STATIC;
+typedef const IFACE_INET_STATIC *LPCIFACE_INET_STATIC;
+
+bool ParseIfaceInet4sParam(const std::vector<std::string> &v, IFACE_INET_STATIC &is);
+bool WriteIfaceInet4sParam(FILE *pf, const IFACE_INET_STATIC &is);
+
+/////////////////////////////////////////////////////////////////////////////
+#endif	//	!defined(AGD_INET4S_H__8DD9BEA3_89E3_42BA_88AC_9D805D2CAEBC__INCLUDED_)

+ 614 - 0
libgfanet/interfaces.cpp

@@ -0,0 +1,614 @@
+#include <string.h>
+#include <regex>
+#include "util.h"
+#include "interfaces.h"
+
+//#define _ETC_NETWORK_INTERFACES			"/etc/network/interfaces"
+#define _ETC_NETWORK_INTERFACES			"/home/wrk/share/gfanet/libgfanet/res/interfaces"
+
+/////////////////////////////////////////////////////////////////////////////
+// iface block
+
+static const char *g_pszCfgGroups[] =
+{
+	"auto",
+	"allow-auto",
+	"allow-hotplug",
+	"no-auto-down",
+	"no-scripts"
+};
+
+static const char *g_pszProtos[] =
+{
+	"inet",
+	"inet6",
+	"ipx",
+	"can"
+};
+
+static const char *g_pszMethods[] =
+{
+	"static",
+	"dhcp",
+	"manual",
+	"bootp",
+	"tunnel",
+	"ppp",
+	"wvdial",
+	"ipv4ll",
+	"loopback",
+	"auto"		// nur IPv6!
+};
+
+static const char *g_pszCommands[] =
+{
+	"pre-up",
+	"up",
+	"post-up",
+	"down",
+	"pre-down",
+	"post-down"
+};
+
+static const char *g_pszIncludes[] =
+{
+	"source",
+	"source-directory"
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+static const char *_GetIfaceProtoStr(IfaceProtos ip)
+{
+	if(ip >= IFP_Inet && ip <= IFP_Can)
+		return g_pszProtos[ip];
+	return "";
+}
+
+static const char *_GetIfaceMethodStr(IfaceMethods im)
+{
+	if(im >= IFM_Static && im <= IFM_Auto)
+		return g_pszMethods[im];
+	return "";
+}
+
+static const char *_GetIfaceCommandsStr(IfaceCommands ic)
+{
+	if(ic >= IFC_PreUp && ic <= IFC_PostDown)
+		return g_pszCommands[ic];
+	return "";
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+CfgGroup ParseCfgGroup(const std::vector<std::string> &v, ITF_CONFIG_GROUP &icg)
+{
+	if(v.size() < 2)
+		return CG_Unknown;
+
+	CfgGroup g = (CfgGroup)FindStringInList(v[0], g_pszCfgGroups, _countof(g_pszCfgGroups));
+
+	if(g > CG_Unknown)
+	{
+		icg._reset();
+		icg.cfgName = v[0];
+		auto vBeg = v.begin();
+		icg.members.insert(icg.members.begin(), ++vBeg, v.end());
+	}
+	else if(g == CG_Unknown && v[0].size() > 6)
+	{
+		if(!v[0].compare(0, 6, "allow-"))
+		{
+			icg._reset();
+			icg.cfgName = v[0];
+			auto vBeg = v.begin();
+			icg.members.insert(icg.members.begin(), ++vBeg, v.end());
+			g = CG_User;
+		}
+	}
+
+	return g;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+IfaceProtos GetIfaceProto(const std::string &s)
+{
+	return (IfaceProtos)FindStringInList(s, g_pszProtos, _countof(g_pszProtos));
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+IfaceMethods GetIfaceMethod(const std::string &s)
+{
+	return (IfaceMethods)FindStringInList(s, g_pszMethods, _countof(g_pszMethods));
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+IfaceCommands GetIfaceCommand(const std::string &s)
+{
+	return (IfaceCommands)FindStringInList(s, g_pszCommands, _countof(g_pszCommands));
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+IfaceHdrType ParseIfaceHeader(const std::vector<std::string> &v, ITF_IFACE_BLOCK &ib)
+{
+	auto vSize = v.size();
+
+	if(	vSize >= 4 &&
+		!v[0].compare("iface"))
+	{
+		ib._reset();
+		ib.cfgName	= v[1];
+
+		int nInheritIdx = 0;
+		
+		for(int i = 2; i < std::min((int)(vSize - 1), 5); i++)
+		{
+			if(!v[i].compare("inherits"))
+			{
+				nInheritIdx = i;
+				ib.inheritedFrom = v[i + 1];
+				break;
+			}
+		}
+
+		if(!nInheritIdx || nInheritIdx > 2)
+			ib.proto	= GetIfaceProto(v[2]);
+		if(!nInheritIdx || nInheritIdx > 3)
+			ib.method	= GetIfaceMethod(v[3]);
+		if(nInheritIdx)
+			return IHR_Unknown;
+
+		switch(ib.proto)
+		{
+		case IFP_Inet:
+			if(ib.method >= IFM_Static && ib.method <= IFM_Loopback)
+				return IHR_OK;
+			return IHR_Invalid;
+		case IFP_Inet6:
+		case IFP_Ipx:
+		case IFP_Can:
+		case IFP_Unknown:
+		default:
+			return IHR_Unknown;
+		}
+	}
+
+	return IHR_NoHdr;
+}
+
+bool ParseIfaceCmd(const std::vector<std::string> &v, std::vector<IFACE_COMMAND> &c)
+{
+	auto vSize = v.size();
+	
+	if(vSize > 1)
+	{
+		IfaceCommands cmd = GetIfaceCommand(v[0]);
+
+		if(cmd >= IFC_PreUp && cmd <= IFC_PostDown)
+		{
+			IFACE_COMMAND ic;
+			ic.cmd = cmd;
+			ic.args = JoinStringArray(v, 1, -1);
+			c.push_back(ic);
+			return true;
+		}
+	}
+	
+	return false;
+}
+
+bool ParseIfaceDesc(const std::vector<std::string> &v, ITF_IFACE_BLOCK &ib)
+{
+	auto vSize = v.size();
+	
+	if(vSize > 1)
+	{
+		if(!v[0].compare("description"))
+		{
+			ib.desc = JoinStringArray(v, 1, -1);
+			return true;
+		}
+	}
+	
+	return false;
+}
+
+bool ParseIfaceParam(const std::vector<std::string> &v, ITF_IFACE_BLOCK &ib)
+{
+	if(ParseIfaceCmd(v, ib.cmds))
+		return true;
+	
+	if(ParseIfaceDesc(v, ib))
+		return true;
+
+	if(ib.proto == IFP_Inet)
+	{
+		switch(ib.method)
+		{
+		case IFM_Static:
+			return ParseIfaceInet4sParam(v, ib.inet4s);
+		case IFM_Dhcp:
+			return ParseIfaceInet4dParam(v, ib.inet4d);
+		case IFM_Manual:
+			return ParseIfaceInet4mParam(v, ib.inet4m);
+		default:
+			break;
+		}
+	}
+
+	return false;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+bool ParseMapping(const std::vector<std::string> &v, ITF_MAPPING_BLOCK &mab)
+{
+	if(v.size() > 1 && !v[0].compare("mapping"))
+	{
+		mab._reset();
+		return true;
+	}
+
+	return false;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+bool ParseIncludes(const std::vector<std::string> &v, ITF_INCLUDE_LIST &inc)
+{
+	if(v.size() > 1)
+	{
+		ITF_INCLUDE ii;
+
+		if(!v[0].compare(g_pszIncludes[0]))
+		{
+			ii.inc = II_File;
+			ii.path = JoinStringArray(v, 1, -1);
+			inc.push_back(ii);
+			return true;
+		}
+		else if(!v[0].compare(g_pszIncludes[1]))
+		{
+			ii.inc = II_Directory;
+			ii.path = JoinStringArray(v, 1, -1);
+			inc.push_back(ii);
+			return true;
+		}
+	}
+
+	return false;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+void ProcessIface(ETC_NETWORK_INTERFACES &eni)
+{
+	for(auto iti = eni.ibl.begin(); iti != eni.ibl.end(); iti++)
+	{
+		ITF_IFACE_BLOCK &ib = *iti;
+
+		if(ib.proto == IFP_Inet && ib.method == IFM_Static)
+		{
+			if(ib.inet4s.netmask.s_addr)
+				ib.inet4s.netprefix = Mask2Prefix(ib.inet4s.netmask);
+			else if(ib.inet4s.netprefix)
+				ib.inet4s.netmask.s_addr = Prefix2Mask(ib.inet4s.netprefix);
+			else
+				ib.inet4s.netprefix = 24;
+		}
+	}
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+void ProcessGroupMembers(ETC_NETWORK_INTERFACES &eni)
+{
+	// remove double configuration names in a single group
+	for(auto cIt = eni.cgl.begin(); cIt != eni.cgl.end(); cIt++)
+	{
+		ITF_CONFIG_GROUP &icg = *cIt;
+		RemoveDoubleStringsFromVector(icg.members);
+	}
+
+	// remove configuration names that don't have an iface block
+
+	// remove redundant configuration names in equally named groups
+	for(auto cIt1 = eni.cgl.begin(); cIt1 != eni.cgl.end(); cIt1++)
+	{
+		ITF_CONFIG_GROUP &icg1 = *cIt1;
+		for(auto cIt2 = cIt1 + 1; cIt2 != eni.cgl.end(); cIt2++)
+		{
+			ITF_CONFIG_GROUP &icg2 = *cIt2;
+			if(!icg1.cfgName.compare(icg2.cfgName))
+			{
+				for(auto sIt = icg1.members.begin(); sIt != icg1.members.end(); sIt++)
+				{
+					const std::string &sMember1 = *sIt;
+					if(RemoveStringFromVector(sMember1, icg2.members))
+						printf("%s\n", sMember1.c_str());
+				}
+			}
+		}
+	}
+
+	for(auto iIt = eni.ibl.begin(); iIt != eni.ibl.end(); iIt++)
+	{
+		ITF_IFACE_BLOCK &ibl = *iIt;
+
+		for(auto cIt = eni.cgl.begin(); cIt != eni.cgl.end(); cIt++)
+		{
+			ITF_CONFIG_GROUP &icg = *cIt;
+
+			for(auto sIt = icg.members.begin(); sIt != icg.members.end(); sIt++)
+			{
+				const std::string &sMember = *sIt;
+
+				if(!ibl.cfgName.compare(sMember))
+				{
+					ibl.memberOf.push_back(&icg);
+				}
+			}
+		}
+	}
+}
+
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+
+int ParseEtcNetworkInterfaces(ETC_NETWORK_INTERFACES &eni)
+{
+	typedef enum ParseStates
+	{
+		PS_Root,
+		PS_Iface,
+		PS_Mapping
+	}ParseStates;
+
+	static const std::string strRegExComt = "^\\s*#.*";
+	static const std::string strRegExLine = "([^\\s]+)";
+	static const std::regex regc(strRegExComt, std::regex_constants::ECMAScript | std::regex_constants::optimize);
+	static const std::regex regl(strRegExLine, std::regex_constants::ECMAScript | std::regex_constants::optimize);
+	std::string buf;
+		
+	eni._reset();
+
+	if(ReadFile(_ETC_NETWORK_INTERFACES, buf) > 0)
+	{
+		ParseStates ps = PS_Root;
+		std::string line;
+		std::istringstream iss(buf);
+		std::istream stm(iss.rdbuf());
+		std::sregex_token_iterator rend;
+		ITF_CONFIG_GROUP icg;
+		ITF_IFACE_BLOCK ib;
+		ITF_MAPPING_BLOCK mab;
+
+        while(std::getline(stm, line))
+		{
+			trim(line);
+
+			if(line.size() > 0)
+			{
+				if(std::regex_match(line, regc))
+					continue;
+
+				CfgGroup cg;
+				IfaceHdrType r1;
+				std::vector<std::string> v;
+
+				if(!SplitString(line, regl, v))
+					continue;
+
+				if((r1 = ParseIfaceHeader(v, ib)) != IHR_NoHdr)
+				{
+					eni.ibl.push_back(ib);
+					ps = PS_Iface;
+				}
+				else if((cg = ParseCfgGroup(v, icg)) != CG_Unknown)
+				{
+					eni.cgl.push_back(icg);
+					ps = PS_Root;
+				}
+				else if(ParseMapping(v, mab))
+				{
+					mab.unparsed.push_back(line);
+					eni.mbl.push_back(mab);
+					ps = PS_Mapping;
+				}
+				else if(ParseIncludes(v, eni.inc))
+				{
+					ps = PS_Root;
+				}
+				else if(ps == PS_Iface)
+				{
+					ITF_IFACE_BLOCK &rib = eni.ibl.back();
+					if(!ParseIfaceParam(v, rib))
+					{
+						rib.unparsed.push_back(line);
+					}
+				}
+				else if(ps == PS_Mapping)
+				{
+					ITF_MAPPING_BLOCK &rmab = eni.mbl.back();
+					rmab.unparsed.push_back(line);
+				}
+				else
+				{
+					eni.unparsed.push_back(line);
+					printf("%d - %s\n", ps, line.c_str());
+				}
+			}
+		}
+
+		ProcessIface(eni);
+		ProcessGroupMembers(eni);
+	}
+
+	return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+
+bool WriteEtcNetworkInterfaces(const ETC_NETWORK_INTERFACES &eni, const char *pszFile)
+{
+	if(!pszFile)
+		pszFile = _ETC_NETWORK_INTERFACES;
+
+	int line;
+	FILE *pf = fopen(pszFile, "wb");
+
+	if(pf)
+	{
+		/////////////////////////////////////////////////////////////////////
+		// write header
+
+		fputs("##############################################################\n", pf);
+		fputs("# interfaces(5) file used by ifup(8) and ifdown(8)\n", pf);
+		fputs("# this file is parsed and rewritten by libgfanet. any existing\n", pf);
+		fputs("# comments will be discarded!\n\n", pf);
+
+		/////////////////////////////////////////////////////////////////////
+		// write mappings
+
+		if(eni.mbl.size() > 0)
+		{
+			fputs("##############################################################\n", pf);
+			fputs("# mapping - not handled by libgfanet\n\n", pf);
+
+			for(auto itm = eni.mbl.begin(); itm != eni.mbl.end(); itm++)
+			{
+				line = 0;
+				const ITF_MAPPING_BLOCK &mb = *itm;
+
+				for(auto its = mb.unparsed.begin(); its != mb.unparsed.end(); its++)
+				{
+					const std::string s = *its;
+					if(line++)
+						fputc('\t', pf);
+					fputs(s.c_str(), pf);
+					fputc('\n', pf);
+				}
+				fputc('\n', pf);
+			}
+		}
+
+		/////////////////////////////////////////////////////////////////////
+		// write config groups
+
+		if(eni.cgl.size() > 0)
+		{
+			fputs("##############################################################\n", pf);
+			fputs("# config groups\n\n", pf);
+
+			for(auto itc = eni.cgl.begin(); itc != eni.cgl.end(); itc++)
+			{
+				line = 0;
+				const ITF_CONFIG_GROUP &cg = *itc;
+
+				if(cg.members.size() > 0)
+				{
+					fputs(cg.cfgName.c_str(), pf);
+
+					for(auto its = cg.members.begin(); its != cg.members.end(); its++)
+					{
+						const std::string &member = *its;
+						fputc(' ', pf);
+						fputs(member.c_str(), pf);
+					}
+					fputc('\n', pf);
+				}
+			}
+			fputc('\n', pf);
+		}
+
+		/////////////////////////////////////////////////////////////////////
+		// write iface
+
+		if(eni.ibl.size() > 0)
+		{
+			fputs("##############################################################\n", pf);
+			fputs("# iface\n\n", pf);
+
+			for(auto iti = eni.ibl.begin(); iti != eni.ibl.end(); iti++)
+			{
+				line = 0;
+				const ITF_IFACE_BLOCK &ib = *iti;
+				
+				if(!ib.inheritedFrom.empty())
+				{
+					fprintf(pf, "iface %s", ib.cfgName.c_str());
+					if(ib.proto != IFP_Unknown)
+					{
+						fputc(' ', pf);
+						fputs(_GetIfaceProtoStr(ib.proto), pf);
+					}
+					if(ib.method != IFM_Unknown)
+					{
+						fputc(' ', pf);
+						fputs(_GetIfaceMethodStr(ib.method), pf);
+					}
+					fprintf(pf, " inherits %s\n", ib.inheritedFrom.c_str());
+					
+				}
+				else
+					fprintf(pf, "iface %s %s %s\n", ib.cfgName.c_str(), _GetIfaceProtoStr(ib.proto), _GetIfaceMethodStr(ib.method));
+
+				if(ib.proto == IFP_Inet)
+				{
+					switch(ib.method)
+					{
+					case IFM_Static:
+						WriteIfaceInet4sParam(pf, ib.inet4s);
+						break;
+					case IFM_Dhcp:
+						WriteIfaceInet4dParam(pf, ib.inet4d);
+						break;
+					case IFM_Manual:
+						WriteIfaceInet4mParam(pf, ib.inet4m);
+						break;
+//					case IFM_Loopback:
+					default:
+						break;
+					}
+				}
+
+				if(ib.cmds.size() > 0)
+				{
+					for(auto itu = ib.cmds.begin(); itu != ib.cmds.end(); itu++)
+					{
+						const IFACE_COMMAND &cmd = *itu;
+						fputc('\t', pf);
+						fputs(_GetIfaceCommandsStr(cmd.cmd), pf);
+						fputc(' ', pf);
+						fputs(cmd.args.c_str(), pf);
+						fputc('\n', pf);
+					}
+				}
+				
+				if(ib.unparsed.size() > 0)
+				{
+					fputs("\t# the following entries are not handled by libgfanet:\n", pf);
+					for(auto itu = ib.unparsed.begin(); itu != ib.unparsed.end(); itu++)
+					{
+						const std::string &line = *itu;
+						fputc('\t', pf);
+						fputs(line.c_str(), pf);
+						fputc('\n', pf);
+					}
+				}
+				fputc('\n', pf);
+			}
+		}
+
+		/////////////////////////////////////////////////////////////////////
+
+		fclose(pf);
+	}
+
+	return false;
+}

+ 220 - 0
libgfanet/interfaces.h

@@ -0,0 +1,220 @@
+// interfaces.h :
+//
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// https://manpages.debian.org/stretch/ifupdown/interfaces.5.en.html
+// https://wiki.debian.org/NetworkConfiguration
+// https://wiki.ubuntuusers.de/interfaces/
+//
+/////////////////////////////////////////////////////////////////////////////
+
+#if !defined(AGD_INTERFACES_H__0F16A7C6_9054_4BBB_8A10_EAE00ED4EE9C__INCLUDED_)
+#define AGD_INTERFACES_H__0F16A7C6_9054_4BBB_8A10_EAE00ED4EE9C__INCLUDED_
+
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <linux/if_packet.h>
+#include <linux/if_arp.h>
+#include <vector>
+#include <string>
+#include "inet4s.h"
+#include "inet4d.h"
+#include "inet4m.h"
+
+/////////////////////////////////////////////////////////////////////////////
+// interfaces.h - Declarations:
+
+typedef struct _ITF_CONFIG_GROUP
+{
+	_ITF_CONFIG_GROUP(){_reset();}
+	void _reset(void)
+	{
+		cfgName.clear();
+		members.clear();
+	}	
+	std::string cfgName;
+	std::vector<std::string> members;
+}ITF_CONFIG_GROUP, *LPITF_CONFIG_GROUP;
+typedef const ITF_CONFIG_GROUP *LPCITF_CONFIG_GROUP;
+typedef std::vector<ITF_CONFIG_GROUP> ITF_CONFIG_GROUP_LIST;
+
+typedef enum CfgGroup
+{
+	CG_Unknown = -1,
+	CG_Auto,
+	CG_AllowAuto,
+	CG_AllowHotplug,
+	CG_NoAutoDown,
+	DG_NoScripts,
+	CG_User
+}CfgGroup;
+
+CfgGroup ParseCfgGroup(const std::vector<std::string> &v, ITF_CONFIG_GROUP &icg);
+
+/////////////////////////////////////////////////////////////////////////////
+
+typedef enum IfaceProtos
+{
+	IFP_Unknown = -1,
+	IFP_Inet,
+	IFP_Inet6,
+	IFP_Ipx,
+	IFP_Can
+}IfaceProtos;
+
+IfaceProtos GetIfaceProto(const std::string &s);
+
+/////////////////////////////////////////////////////////////////////////////
+
+typedef enum IfaceMethods
+{
+	IFM_Unknown = -1,
+	IFM_Static,
+	IFM_Dhcp,
+	IFM_Manual,
+	IFM_BootP,
+	IFM_Tunnel,
+	IFM_Ppp,
+	IFM_WvDial,
+	IFM_IpV4ll,
+	IFM_Loopback,
+	IFM_Auto
+}IfaceMethods;
+
+IfaceMethods GetIfaceMethod(const std::string &s);
+
+/////////////////////////////////////////////////////////////////////////////
+
+typedef enum IfaceCommands
+{
+	IFC_Unknown = -1,
+	IFC_PreUp,
+	IFC_Up,
+	IFC_PostUp,
+	IFC_Down,
+	IFC_PreDown,
+	IFC_PostDown
+}IfaceCommands;
+
+typedef struct _IFACE_COMMAND
+{
+	IfaceCommands cmd;
+	std::string args;
+}IFACE_COMMAND, *LPIFACE_COMMAND;
+typedef const IFACE_COMMAND *LPCIFACE_COMMAND;
+
+IfaceCommands GetIfaceCommand(const std::string &s);
+bool ParseIfaceCmd(const std::vector<std::string> &v, std::vector<IFACE_COMMAND> &c);
+
+/////////////////////////////////////////////////////////////////////////////
+
+typedef enum ItfInclude
+{
+	II_None = -1,
+	II_File,
+	II_Directory
+}ItfInclude;
+
+typedef struct _ITF_INCLUDE
+{
+	ItfInclude inc;
+	std::string path;
+}ITF_INCLUDE, *LPITF_INCLUDE;
+typedef const ITF_INCLUDE *LPCITF_INCLUDE;
+typedef std::vector<ITF_INCLUDE> ITF_INCLUDE_LIST;
+
+bool ParseIncludes(const std::vector<std::string> &v, ITF_INCLUDE_LIST &inc);
+
+/////////////////////////////////////////////////////////////////////////////
+
+typedef struct _ITF_IFACE_BLOCK
+{
+	_ITF_IFACE_BLOCK(){_reset();}
+	void _reset(void)
+	{
+		cfgName.clear();
+		proto = IFP_Unknown;
+		method = IFM_Unknown;
+		inheritedFrom.clear();
+		desc.clear();
+		cmds.clear();
+		memberOf.clear();
+		unparsed.clear();
+		inet4s._reset();
+		inet4d._reset();
+		inet4m._reset();
+	}
+	std::string cfgName;
+	IfaceProtos proto;
+	IfaceMethods method;
+	std::string inheritedFrom;
+	std::string desc;
+	std::vector<IFACE_COMMAND> cmds;
+	std::vector<LPITF_CONFIG_GROUP> memberOf;
+	std::vector<std::string> unparsed;
+	IFACE_INET_STATIC inet4s;
+	IFACE_INET_DHCP inet4d;
+	IFACE_INET_MANUAL inet4m;
+}ITF_IFACE_BLOCK, *LPITF_IFACE_BLOCK;
+typedef const ITF_IFACE_BLOCK *LPCITF_IFACE_BLOCK;
+typedef std::vector<ITF_IFACE_BLOCK> ITF_IFACE_BLOCK_LIST;
+
+typedef enum IfaceHdrType
+{
+	IHR_NoHdr,
+	IHR_Invalid,
+	IHR_Unknown,
+	IHR_OK
+}IfaceHdrType;
+
+IfaceHdrType ParseIfaceHeader(const std::vector<std::string> &v, ITF_IFACE_BLOCK &ib);
+bool ParseIfaceParam(const std::vector<std::string> &v, ITF_IFACE_BLOCK &ib);
+bool ParseIfaceDesc(const std::vector<std::string> &v, ITF_IFACE_BLOCK &ib);
+
+/////////////////////////////////////////////////////////////////////////////
+
+typedef struct _ITF_MAPPING_BLOCK
+{
+	_ITF_MAPPING_BLOCK(){_reset();}
+	void _reset(void)
+	{
+		unparsed.clear();
+	}
+	std::vector<std::string> unparsed;
+}ITF_MAPPING_BLOCK, *LPITF_MAPPING_BLOCK;
+typedef const ITF_MAPPING_BLOCK *LPCITF_MAPPING_BLOCK;
+typedef std::vector<ITF_MAPPING_BLOCK> ITF_MAPPING_BLOCK_LIST;
+
+bool ParseMapping(const std::vector<std::string> &v, ITF_MAPPING_BLOCK &mab);
+
+/////////////////////////////////////////////////////////////////////////////
+
+typedef struct _ETC_NETWORK_INTERFACES
+{
+	_ETC_NETWORK_INTERFACES(void){_reset();}
+	void _reset(void)
+	{
+		cgl.clear();
+		mbl.clear();
+		ibl.clear();
+		inc.clear();
+	}
+	ITF_CONFIG_GROUP_LIST	cgl;
+	ITF_MAPPING_BLOCK_LIST	mbl;
+	ITF_IFACE_BLOCK_LIST	ibl;
+	ITF_INCLUDE_LIST		inc;
+	std::vector<std::string> unparsed;
+}ETC_NETWORK_INTERFACES, *LPETC_NETWORK_INTERFACES;
+typedef const ETC_NETWORK_INTERFACES *LPCETC_NETWORK_INTERFACES;
+
+void ProcessIface(ETC_NETWORK_INTERFACES &eni);
+void ProcessGroupMembers(ETC_NETWORK_INTERFACES &eni);
+int ParseEtcNetworkInterfaces(ETC_NETWORK_INTERFACES &eni);
+bool WriteEtcNetworkInterfaces(const ETC_NETWORK_INTERFACES &eni, const char *pszFile = NULL);
+
+/////////////////////////////////////////////////////////////////////////////
+#endif	//	!defined(AGD_INTERFACES_H__0F16A7C6_9054_4BBB_8A10_EAE00ED4EE9C__INCLUDED_)

+ 238 - 0
libgfanet/util.cpp

@@ -0,0 +1,238 @@
+#include <malloc.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <functional>
+#include <algorithm>
+#include "util.h"
+
+//////////////////////////////////////////////////////////////////////////////////
+// strucase
+
+std::string & strucase(std::string &s)
+{
+	std::transform(s.begin(), s.end(), s.begin(), ::toupper);
+	return s;
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// strlcase
+
+std::string & strlcase(std::string &s)
+{
+	std::transform(s.begin(), s.end(), s.begin(), ::tolower);
+	return s;
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// trim from start (in place)
+
+std::string & ltrim(std::string &s)
+{
+    s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun<int, int>(std::isspace))));
+	return s;
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// trim from end (in place)
+
+std::string & rtrim(std::string &s)
+{
+    s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
+	return s;
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// trim from both ends (in place)
+
+std::string & trim(std::string &s)
+{
+    return ltrim(rtrim(s));
+}
+
+std::string trim(const std::string &s)
+{
+	std::string t(s);
+    return ltrim(rtrim(t));
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+// SplitString
+
+size_t SplitString(const std::string &str, const std::regex &reg, std::vector<std::string> &vec)
+{
+	const std::sregex_token_iterator end;
+	for(std::sregex_token_iterator iter(str.begin(), str.end(), reg); iter != end; ++iter)
+		vec.push_back(*iter);
+	return vec.size();
+}
+
+size_t SplitString(const std::string &str, const char *regxsplit, std::vector<std::string> &vec)
+{
+	const std::regex reg(regxsplit);
+	return SplitString(str, reg, vec);
+/*	const std::sregex_token_iterator end;
+	for(std::sregex_token_iterator iter(str.begin(), str.end(), reg); iter != end; ++iter)
+		vec.push_back(*iter);*/
+}
+
+std::string JoinStringArray(const std::vector<std::string> &vec, int nPosStart, int nPosEnd, const char *sep)
+{
+	auto vSize = vec.size();
+	
+	if(	vSize > 0 &&
+		nPosStart < (int)vSize &&
+		nPosEnd < (int)vSize)
+	{
+		std::ostringstream os;
+		auto itBegin	= (nPosStart <= 0) ? vec.begin() : vec.begin() + nPosStart;
+		auto itEnd		= (nPosEnd < 0) ? vec.end() : vec.begin() + (nPosEnd + 1);
+
+		if(itBegin != itEnd)
+			os << *itBegin++;
+		while(itBegin != itEnd)
+		{
+			os << sep;
+			os << *itBegin++;
+		}
+
+		return os.str();
+	}
+	
+	return "";
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+
+ssize_t ReadFile(const char *pszPath, void **ppBuf, size_t nBlockSize)
+{
+	if(!ppBuf)
+		return -1;
+	*ppBuf = NULL;
+
+	if(!nBlockSize)
+		nBlockSize = sysconf(_SC_PAGESIZE);
+
+	int fd;
+	ssize_t l, nRead = 0;
+
+	if((fd = open(pszPath, O_RDONLY)) == -1)
+		return -1;
+
+//	off_t size = lseek(fd, 0, SEEK_END);
+//	perror("lseek - ");
+
+	char *p = (char*)malloc(nBlockSize);
+
+	while((l = read(fd, p + nRead, nBlockSize)) == (ssize_t)nBlockSize)
+	{
+		nRead += l;
+		p = (char*)realloc(p, nRead + nBlockSize);
+	}
+
+	close(fd);
+
+	if(l == -1)
+	{
+		free(p);
+		return -1;
+	}
+
+	nRead += l;
+	p[nRead] = '\n';
+	*ppBuf = p;
+	return nRead;
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+
+ssize_t ReadFile(const char *pszPath, std::string &str)
+{
+	char *pszBuf;
+	ssize_t nRet = ReadFile(pszPath, (void**)&pszBuf, 0);
+
+	if(nRet > 0)
+		str = pszBuf;
+	if(pszBuf)
+		free(pszBuf);
+	return nRet;
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+
+int FindStringInList(const std::string &str, const char *pszList[], size_t nCntList)
+{
+	for(size_t i = 0; i < nCntList; i++)
+	{
+		if(!str.compare(pszList[i]))
+			return i;
+	}
+
+	return -1;
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+
+int RemoveDoubleStringsFromVector(std::vector<std::string> &vec)
+{
+	int nRet = 0;
+
+	for(auto it1 = vec.begin(); it1 != vec.end(); ++it1)
+	{
+		const std::string &str1 = *it1;
+
+		for(auto it2 = it1 + 1; it2 != vec.end(); )
+		{
+			const std::string &str2 = *it2;
+
+			if(!str1.compare(str2))
+			{
+		        it2 = vec.erase(it2);
+		        nRet++;
+		    }
+			else
+				++it2;
+		}
+	}
+
+	return nRet;
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+
+int RemoveStringFromVector(const std::string &str, std::vector<std::string> &vec)
+{
+	int nRet = 0;
+
+	for(auto it = vec.begin(); it != vec.end(); )
+	{
+		const std::string &str2 = *it;
+
+		if(!str.compare(str2))
+		{
+	        it = vec.erase(it);
+	        nRet++;
+	    }
+		else
+			++it;
+	}
+
+	return nRet;
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+
+std::vector<std::string>::iterator FindString(const std::string &str, std::vector<std::string> &vec)
+{
+	auto it = vec.begin();
+
+	for(; it != vec.end(); it++)
+	{
+		if(!str.compare(*it))
+			break;
+	}
+
+	return it;
+}

+ 89 - 0
libgfanet/util.h

@@ -0,0 +1,89 @@
+// util.h :
+//
+
+#if !defined(AGD_UTIL_H__B15256F1_198D_4061_918A_A8B05FF98364__INCLUDED_)
+#define AGD_UTIL_H__B15256F1_198D_4061_918A_A8B05FF98364__INCLUDED_
+
+#include <stdio.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <string>
+#include <vector>
+#include <regex>
+
+/////////////////////////////////////////////////////////////////////////////
+// util.h - Declarations:
+
+#define _READ_BLOCK_SIZE				4096
+#define _countof(a)						(sizeof(a) / sizeof(*a))
+
+/////////////////////////////////////////////////////////////////////////////
+
+std::string & strucase(std::string &s);
+std::string & strlcase(std::string &s);
+std::string & ltrim(std::string &s);
+std::string & rtrim(std::string &s);
+std::string & trim(std::string &s);
+std::string   trim(const std::string &s);
+
+size_t SplitString(const std::string &str, const char *regxsplit, std::vector<std::string> &vec);
+size_t SplitString(const std::string &str, const std::regex &reg, std::vector<std::string> &vec);
+std::string JoinStringArray(const std::vector<std::string> &vec, int nPosStart = 0, int nPosEnd = -1, const char *sep = " ");
+
+template<typename T>
+inline unsigned int BitCount(T n)
+{
+	unsigned int count = 0;
+	while(n)
+	{
+		count++;
+		n &= (n - 1);
+	}
+	return count;
+}
+
+inline int Mask2Prefix(const struct in_addr &in)
+{
+	return BitCount(in.s_addr);
+}
+
+inline in_addr_t Prefix2Mask(int prefix)
+{
+	return htonl(~((1 << (32 - prefix)) - 1));
+}
+
+inline bool IsPowerOf2(unsigned int x)
+{
+	return x && !(x & (x - 1));
+}
+
+inline bool IsValidNetmask(const struct in_addr &in)
+{
+	return IsPowerOf2(~ntohl(in.s_addr) + 1);
+}
+
+inline bool IsDecimalInt(const char *pszNum)
+{
+	if(pszNum && *pszNum)
+	{
+		while(*pszNum)
+		{
+			if(!isdigit(*pszNum) && *pszNum != '+' && *pszNum != '-')
+				return false;
+			pszNum++;
+		}
+		return true;
+	}
+	return false;
+}
+
+ssize_t ReadFile(const char *pszPath, void **ppBuf, size_t nBlockSize = _READ_BLOCK_SIZE);
+ssize_t ReadFile(const char *pszPath, std::string &str);
+int FindStringInList(const std::string &str, const char *pszList[], size_t nCntList);
+std::vector<std::string>::iterator FindString(const std::string &str, std::vector<std::string> &vec);
+int RemoveStringFromVector(const std::string &str, std::vector<std::string> &vec);
+int RemoveDoubleStringsFromVector(std::vector<std::string> &vec);
+	
+/////////////////////////////////////////////////////////////////////////////
+#endif	//	!defined(AGD_UTIL_H__B15256F1_198D_4061_918A_A8B05FF98364__INCLUDED_)