Вот как-то так:
=========================================
nm-autovpn.c
=========================================
// Some code has been taken from NetworkManager and nm-applet
#include <glib.h>
#include <dbus/dbus.h>
#include <dbus/dbus-glib.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <nm-device.h>
#include <nm-client.h>
#include <nm-dbus-connection.h>
#include <nm-dbus-settings.h>
#include <nm-setting-connection.h>
#include <nm-vpn-connection.h>
#define DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH (dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH))
#define DBUS_TYPE_G_MAP_OF_VARIANT (dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE))
#define DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT (dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, DBUS_TYPE_G_MAP_OF_VARIANT))
#define _DEBUGGING_
static GHashTable *user_connections = NULL;
static GHashTable *system_connections = NULL;
static DBusGConnection *system_bus = NULL;
static NMClient *client = NULL;
static NMConnection*
get_one_connection (const char* path, NMConnectionScope scope)
{
DBusGProxy *proxy;
const char *service;
NMConnection *connection = NULL;
GError *error = NULL;
GHashTable *settings = NULL;
if(!(system_bus||path))
return NULL;
service = (scope == NM_CONNECTION_SCOPE_SYSTEM) ?
NM_DBUS_SERVICE_SYSTEM_SETTINGS : NM_DBUS_SERVICE_USER_SETTINGS;
proxy = dbus_g_proxy_new_for_name (system_bus, service, path,
NM_DBUS_IFACE_SETTINGS_CONNECTION);
if (!proxy) {
g_warning ("%s: failed to create DBus proxy for %s, path: %s", __func__, service, path);
return NULL;
}
if (!dbus_g_proxy_call (proxy, "GetSettings", &error,
G_TYPE_INVALID,
DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, &settings,
G_TYPE_INVALID)) {
g_warning ("%s: cannot retrieve connection: %s", __func__, error ? error->message : "(unknown)");
goto error;
}
connection = nm_connection_new_from_hash (settings, &error);
g_hash_table_destroy (settings);
if (!connection) {
g_warning ("%s: invalid connection: '%s' / '%s' invalid: %d",
__func__,
error ? g_type_name (nm_connection_lookup_setting_type_by_quark (error->domain)) : "(unknown)",
error ? error->message : "(unknown)",
error ? error->code : -1);
goto error;
}
nm_connection_set_scope (connection, scope);
nm_connection_set_path (connection, path);
return g_object_ref (connection);
error:
g_clear_error (&error);
if (connection)
g_object_unref (connection);
g_object_unref (proxy);
return NULL;
}
static GHashTable*
get_connections_for_service (NMConnectionScope scope)
{
GHashTable *result = NULL;
GError *error = NULL;
DBusGProxy *proxy;
GPtrArray *paths = NULL;
const char *service;
int i;
service = (scope == NM_CONNECTION_SCOPE_SYSTEM) ?
NM_DBUS_SERVICE_SYSTEM_SETTINGS : NM_DBUS_SERVICE_USER_SETTINGS;
proxy = dbus_g_proxy_new_for_name (system_bus, service,
NM_DBUS_PATH_SETTINGS, NM_DBUS_IFACE_SETTINGS);
if (!proxy) {
g_warning ("%s: failed to create DBus proxy for %s", __func__, service);
return NULL;
}
if (!dbus_g_proxy_call (proxy, "ListConnections", &error,
G_TYPE_INVALID,
DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH, &paths,
G_TYPE_INVALID)) {
g_warning ("%s: failed to read connections from %s:\n %s",
__func__, service, error ? error->message : "(unknown)");
g_clear_error (&error);
goto out;
}
result = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
for (i = 0; paths && (i < paths->len); i++) {
NMConnection *connection;
connection = get_one_connection (g_ptr_array_index (paths, i), scope);
if (connection)
g_hash_table_insert (result, g_ptr_array_index (paths, i), connection);
}
out:
g_object_unref (proxy);
return result;
}
static NMConnection*
find_connection_by_uuid (GHashTable* connections, const char* uuid)
{
NMSettingConnection *setting;
GHashTableIter iter;
gpointer path, conn;
g_hash_table_iter_init (&iter, connections);
while (g_hash_table_iter_next (&iter, &path, &conn)) {
setting = NM_SETTING_CONNECTION(nm_connection_get_setting (conn, NM_TYPE_SETTING_CONNECTION));
if (setting && g_strcmp0(uuid, nm_setting_connection_get_uuid (setting)) == 0)
return conn;
}
return NULL;
}
static NMActiveConnection *
get_default_active_connection (NMDevice **device)
{
NMActiveConnection *default_ac = NULL;
NMDevice *non_default_device = NULL;
NMActiveConnection *non_default_ac = NULL;
const GPtrArray *active_connections;
int i;
g_return_val_if_fail (device != NULL, NULL);
g_return_val_if_fail (*device == NULL, NULL);
active_connections = nm_client_get_active_connections (client);
for (i = 0; active_connections && (i < active_connections->len); i++) {
NMActiveConnection *candidate = g_ptr_array_index (active_connections, i);
const GPtrArray *devices;
devices = nm_active_connection_get_devices (candidate);
if (!devices || !devices->len)
continue;
if (nm_active_connection_get_default (candidate)) {
if (!default_ac) {
*device = g_ptr_array_index (devices, 0);
default_ac = candidate;
}
} else {
if (!non_default_ac) {
non_default_device = g_ptr_array_index (devices, 0);
non_default_ac = candidate;
}
}
}
/* Prefer the default connection if one exists, otherwise return the first
* non-default connection.
*/
if (!default_ac && non_default_ac) {
default_ac = non_default_ac;
*device = non_default_device;
}
return default_ac;
}
static void
vpn_connect(NMClient *client, const char* uuid)
{
NMConnection *connection = NULL;
NMActiveConnection *active = NULL;
NMDevice* device = NULL;
gboolean is_system = FALSE;
sleep (3);
connection = find_connection_by_uuid (user_connections, uuid);
if (!connection) {
connection = find_connection_by_uuid (system_connections, uuid);
is_system = TRUE;
}
g_return_if_fail (connection);
active = get_default_active_connection (&device);
if (!active || !device) {
g_warning ("%s: no active connection or device.", __func__);
return;
}
nm_client_activate_connection (client,
is_system ? NM_DBUS_SERVICE_SYSTEM_SETTINGS: NM_DBUS_SERVICE_USER_SETTINGS,
nm_connection_get_path (connection),
device,
nm_object_get_path (NM_OBJECT (active)),
NULL,
NULL);
}
static void
vpn_connection_state_changed (NMVPNConnection *vpn,
NMVPNConnectionState state,
NMVPNConnectionStateReason reason,
gpointer user_data)
{
if (state == NM_VPN_CONNECTION_STATE_FAILED || state == NM_VPN_CONNECTION_STATE_DISCONNECTED) {
if (reason != NM_VPN_CONNECTION_STATE_REASON_USER_DISCONNECTED)
vpn_connect (client, user_data);
}
}
static void
active_connections_changed_cb (NMClient *client,
GParamSpec *pspec,
gpointer user_data)
{
const GPtrArray *active_list;
int i;
/* Track the state of new VPN connections */
active_list = nm_client_get_active_connections (client);
for (i = 0; active_list && (i < active_list->len); i++) {
NMActiveConnection *candidate = NM_ACTIVE_CONNECTION (g_ptr_array_index (active_list, i));
guint id;
if ( !NM_IS_VPN_CONNECTION (candidate)
|| g_object_get_data (G_OBJECT (candidate), "vpn-state-id"))
continue;
id = g_signal_connect (G_OBJECT (candidate), "vpn-state-changed",
G_CALLBACK (vpn_connection_state_changed), user_data);
g_object_set_data (G_OBJECT (candidate), "vpn-state-id", GUINT_TO_POINTER (id));
}
}
int
main (int argc, char* argv[])
{
GError *error = NULL;
GMainLoop *loop = NULL;
g_type_init ();
sleep (3);
system_bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
if (error || !system_bus)
{
g_warning("error: could not connect to system bus");
return FALSE;
}
#ifdef _DEBUGGING_
g_warning("Point 1");
#endif
client = nm_client_new ();
if(!client)
{
g_warning ("error: could not create NMClient object");
exit (1);
}
#ifdef _DEBUGGING_
g_warning("Point 2");
#endif
if(nm_client_get_state(client)!=NM_STATE_CONNECTED)
{
g_error ("could not connect to NetworkManager");
exit (1);
}
#ifdef _DEBUGGING_
g_warning("Point 3");
#endif
user_connections=get_connections_for_service(NM_CONNECTION_SCOPE_USER);
system_connections = get_connections_for_service(NM_CONNECTION_SCOPE_SYSTEM);
vpn_connect(client, argv[1]);
g_signal_connect(client, "notify::active-connections",G_CALLBACK (active_connections_changed_cb),argv[1]);
#ifdef _DEBUGGING_
g_warning("Point 4");
#endif
//return 0;
/* loop = g_main_loop_new (NULL, FALSE);
g_main_loop_run (loop);
g_main_loop_unref (loop);*/
#ifdef _DEBUGGING_
g_warning("Point 5");
#endif
g_object_unref (client);
if (user_connections)
g_hash_table_unref (user_connections);
#ifdef _DEBUGGING_
g_warning("Point 6");
#endif
if (system_connections)
g_hash_table_unref (system_connections);
#ifdef _DEBUGGING_
g_warning("Point 7");
#endif
dbus_g_connection_unref(system_bus);
#ifdef _DEBUGGING_
g_warning("Point 8");
#endif
return 0;
}
=========================================
nmrd.c
=========================================
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <signal.h>
#include <resolv.h>
#include <arpa/inet.h>
#include <netinet/ip_icmp.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <sys/time.h>
#include <netdb.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#define BUFSIZE 1500
//#define _DEBUG_
#define PROBE_COUNT 4
#define MIN_TIMEOUT 3
#define MIN_INTERVAL 30
#define MAX_INTERVAL 3600
socklen_t salen; /* length of sockaddr{}s */
struct sockaddr *sasend; /* sockaddr{} for send, from getaddrinfo */
struct sockaddr *sarecv; /* sockaddr{} for receiving */
#define TIMEOUT_KEY "-t:"
#define INTERVAL_KEY "-i:"
#define HOST_KEY "-h:"
#define CONNECT_KEY "-c:"
const int datalen=56; /* data that goes with ICMP echo request */
int nsent=0;
int _sock;
int tout=MIN_TIMEOUT;
int interval=MIN_INTERVAL;
int probes=PROBE_COUNT;
char *conn_id=NULL;
char *host=NULL;
struct addrinfo *ai=NULL;
#include <sys/param.h>
typedef union {
char c[2];
u_short s;
} short_union_t;
typedef union {
u_short s[2];
long l;
} long_union_t;
static __inline__ void
reduce(int * sum)
{
long_union_t l_util;
l_util.l = *sum;
*sum = l_util.s[0] + l_util.s[1];
if (*sum > 65535)
*sum -= 65535;
return;
}
unsigned short in_cksum(void * pkt, int len)
{
u_short * w = (u_short *)pkt;
int sum = 0;
w = (u_short *)pkt;
while ((len -= 32) >= 0) {
sum += w[0]; sum += w[1];
sum += w[2]; sum += w[3];
sum += w[4]; sum += w[5];
sum += w[6]; sum += w[7];
sum += w[8]; sum += w[9];
sum += w[10]; sum += w[11];
sum += w[12]; sum += w[13];
sum += w[14]; sum += w[15];
w += 16;
}
len += 32;
while ((len -=

>= 0) {
sum += w[0]; sum += w[1];
sum += w[2]; sum += w[3];
w += 4;
}
len += 8;
if (len) {
reduce(&sum);
while ((len -= 2) >= 0) {
sum += *w++;
}
}
if (len == -1) { /* odd-length packet */
short_union_t s_util;
s_util.s = 0;
s_util.c[0] = *((char *)w);
s_util.c[1] = 0;
sum += s_util.s;
}
reduce(&sum);
return (~sum & 0xffff);
}
void tv_sub(struct timeval *out, struct timeval *in)
{
if ( (out->tv_usec -= in->tv_usec) < 0) { /* out -= in */
--out->tv_sec;
out->tv_usec += 1000000;
}
out->tv_sec-=in->tv_sec;
}
void fproc(char *ptr, ssize_t len, struct timeval *tvrecv)
{
int hlen1, icmplen;
double rtt;
struct ip *ip;
struct icmp *icmp;
struct timeval *tvsend;
ip = (struct ip *) ptr; /* start of IP header */
hlen1 = ip->ip_hl << 2; /* length of IP header */
icmp = (struct icmp *) (ptr + hlen1); /* start of ICMP header */
if ((icmplen=len-hlen1)<

return;
if (icmp->icmp_type == ICMP_ECHOREPLY)
{
if(icmp->icmp_id!=getpid())
return; /* not a response to our ECHO_REQUEST */
if(icmplen<0x10)
return;
}
}
void fsend(void)
{
char sendbuf[BUFSIZE];
int len;
struct icmp *icmp;
icmp=(struct icmp *)sendbuf;
icmp->icmp_type=ICMP_ECHO;
icmp->icmp_code=0;
icmp->icmp_id=getpid();
icmp->icmp_seq=nsent++;
gettimeofday((struct timeval *) icmp->icmp_data, NULL);
len = 8 + datalen; /* checksum ICMP header and data */
icmp->icmp_cksum = 0;
icmp->icmp_cksum = in_cksum((u_short *) icmp, len);
ssize_t bytes_sent=sendto(_sock, sendbuf, len, 0, sasend, salen);
}
using namespace std;
struct addrinfo *hostServ(const char *host, const char *serv, int family, int socktype)
{
int n=0;
struct addrinfo hints = {AI_CANONNAME, family, socktype, 0, 0, NULL, NULL, NULL};
struct addrinfo *res=NULL;
return (n=getaddrinfo(host,serv,&hints,&res))?NULL:res;
}
bool do_ping()
{
char recvbuf[BUFSIZE];
sasend = ai->ai_addr;
sarecv=(sockaddr *)calloc(1,ai->ai_addrlen);
salen = ai->ai_addrlen;
_sock=socket(sasend->sa_family,SOCK_RAW,IPPROTO_ICMP);
if(!_sock)
return false;
int size=60*0x400;
struct timeval tv;
tv.tv_sec=tout; /* 10 Secs Timeout */
tv.tv_usec=0;
setsockopt(_sock,SOL_SOCKET,SO_RCVTIMEO,(struct timeval *)&tv,sizeof(struct timeval));
setsockopt(_sock,SOL_SOCKET,SO_RCVBUF,&size,sizeof(size));
for(int i=0;i<PROBE_COUNT;i++)
{
fsend();
struct timeval tval={};
socklen_t len=salen;
int n=recvfrom(_sock,recvbuf,sizeof(recvbuf),0,sarecv,&len);
if(n<0)
{
switch(errno)
{
case ETIMEDOUT:
{
break;
}
case EINTR:
{
break;
}
case EAGAIN:
{
close(_sock);
return false;
}
default:
{
close(_sock);
return false;
}
}
}
else
{
gettimeofday(&tval, NULL);
fproc(recvbuf, n, &tval);
close(_sock);
return true;
}
}
close(_sock);
return false;
}
bool reconnect()
{
// printf("%s\n",conn_id);
return true;
}
int main(int argc, char ** argv)
{
for(int i=1;i<argc;i++)
{
if(strstr(argv
,TIMEOUT_KEY))
tout=atoi(&argv[strlen(TIMEOUT_KEY)]);
if(strstr(argv,CONNECT_KEY))
conn_id=&argv[strlen(CONNECT_KEY)];
if(strstr(argv,HOST_KEY))
host=&argv[strlen(HOST_KEY)];
if(strstr(argv,INTERVAL_KEY))
interval=atoi(&argv[strlen(INTERVAL_KEY)]);
}
if(!conn_id)
{
return -1;
}
if(!host)
{
return -2;
}
ai=hostServ(host, NULL, 0, 0);
if(tout<MIN_TIMEOUT)
tout=MIN_TIMEOUT;
if(interval<MIN_INTERVAL)
tout=MIN_INTERVAL;
if(interval>MAX_INTERVAL)
interval=MAX_INTERVAL;
if(!do_ping())
reconnect();
return 0;
}
=========================================
Makefile:
=========================================
# Makefile for autovpn
nmrd: nmrd.o nm-autovpn.o
g++ -o nmrd nmrd.o nm-autovpn.o
nmrd.o: nmrd.c
g++ -c nmrd.c
nm-autovpn.o: nm-autovpn.c
gcc -c `pkg-config --cflags --libs libnm_glib libnm-util` nm-autovpn.c
clean:
rm -f *.o nmrd
Под 9.04 работало. Если нужны подробности - допишу.