Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Move set_script_env() to script.c
Let's move the environment stuff out of the way so that tun.c can be built
for sane platforms only.

Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
  • Loading branch information
David Woodhouse authored and David Woodhouse committed Feb 13, 2014
1 parent 5533428 commit 8f2d1a5
Show file tree
Hide file tree
Showing 4 changed files with 312 additions and 272 deletions.
3 changes: 2 additions & 1 deletion Makefile.am
Expand Up @@ -18,7 +18,8 @@ openconnect_SOURCES = xml.c main.c
openconnect_CFLAGS = $(AM_CFLAGS) $(SSL_CFLAGS) $(DTLS_SSL_CFLAGS) $(LIBXML2_CFLAGS) $(LIBPROXY_CFLAGS) $(ZLIB_CFLAGS) $(LIBSTOKEN_CFLAGS) $(LIBOATH_CFLAGS)
openconnect_LDADD = libopenconnect.la $(LIBXML2_LIBS) $(LIBPROXY_LIBS) $(LIBINTL)

library_srcs = ssl.c http.c auth.c library.c compat.c dtls.c cstp.c mainloop.c tun.c
library_srcs = ssl.c http.c auth.c library.c compat.c dtls.c cstp.c \
mainloop.c tun.c script.c
lib_srcs_gnutls = gnutls.c gnutls_pkcs12.c gnutls_tpm.c
lib_srcs_openssl = openssl.c

Expand Down
4 changes: 4 additions & 0 deletions openconnect-internal.h
Expand Up @@ -448,6 +448,10 @@ int dumb_socketpair(int socks[2], int make_overlapped);
/* tun-win32.c */
int win32_setup_tun(struct openconnect_info *vpninfo);

/* script.c */
int setenv_int(const char *opt, int value);
void set_script_env(struct openconnect_info *vpninfo);

/* tun.c */
int tun_mainloop(struct openconnect_info *vpninfo, int *timeout);
void shutdown_tun(struct openconnect_info *vpninfo);
Expand Down
306 changes: 306 additions & 0 deletions script.c
@@ -0,0 +1,306 @@
/*
* OpenConnect (SSL + DTLS) VPN client
*
* Copyright © 2008-2014 Intel Corporation.
*
* Author: David Woodhouse <dwmw2@infradead.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/

#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#ifndef _WIN32
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <net/if.h>
#endif
#include <errno.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>

#include "openconnect-internal.h"

int setenv_int(const char *opt, int value)
{
char buf[16];
sprintf(buf, "%d", value);
return setenv(opt, buf, 1);
}

static int netmasklen(struct in_addr addr)
{
int masklen;

for (masklen = 0; masklen < 32; masklen++) {
if (ntohl(addr.s_addr) >= (0xffffffff << masklen))
break;
}
return 32 - masklen;
}

static int process_split_xxclude(struct openconnect_info *vpninfo,
int include, const char *route, int *v4_incs,
int *v6_incs)
{
struct in_addr addr;
const char *in_ex = include ? "IN" : "EX";
char envname[80];
char *slash;

slash = strchr(route, '/');
if (!slash) {
badinc:
if (include)
vpn_progress(vpninfo, PRG_ERR,
_("Discard bad split include: \"%s\"\n"),
route);
else
vpn_progress(vpninfo, PRG_ERR,
_("Discard bad split exclude: \"%s\"\n"),
route);
return -EINVAL;
}

*slash = 0;

if (strchr(route, ':')) {
snprintf(envname, 79, "CISCO_IPV6_SPLIT_%sC_%d_ADDR", in_ex,
*v6_incs);
setenv(envname, route, 1);

snprintf(envname, 79, "CISCO_IPV6_SPLIT_%sC_%d_MASKLEN", in_ex,
*v6_incs);
setenv(envname, slash+1, 1);

(*v6_incs)++;
return 0;
}

if (!inet_aton(route, &addr)) {
*slash = '/';
goto badinc;
}

envname[79] = 0;
snprintf(envname, 79, "CISCO_SPLIT_%sC_%d_ADDR", in_ex, *v4_incs);
setenv(envname, route, 1);

/* Put it back how we found it */
*slash = '/';

if (!inet_aton(slash+1, &addr))
goto badinc;

snprintf(envname, 79, "CISCO_SPLIT_%sC_%d_MASK", in_ex, *v4_incs);
setenv(envname, slash+1, 1);

snprintf(envname, 79, "CISCO_SPLIT_%sC_%d_MASKLEN", in_ex, *v4_incs);
setenv_int(envname, netmasklen(addr));

(*v4_incs)++;
return 0;
}

static int appendenv(const char *opt, const char *new)
{
char buf[1024];
char *old = getenv(opt);

buf[1023] = 0;
if (old)
snprintf(buf, 1023, "%s %s", old, new);
else
snprintf(buf, 1023, "%s", new);

return setenv(opt, buf, 1);
}

static void setenv_cstp_opts(struct openconnect_info *vpninfo)
{
char *env_buf;
int buflen = 0;
int bufofs = 0;
struct oc_vpn_option *opt;

for (opt = vpninfo->cstp_options; opt; opt = opt->next)
buflen += 2 + strlen(opt->option) + strlen(opt->value);

env_buf = malloc(buflen + 1);
if (!env_buf)
return;

env_buf[buflen] = 0;

for (opt = vpninfo->cstp_options; opt; opt = opt->next)
bufofs += snprintf(env_buf + bufofs, buflen - bufofs,
"%s=%s\n", opt->option, opt->value);

setenv("CISCO_CSTP_OPTIONS", env_buf, 1);
free(env_buf);
}

static void set_banner(struct openconnect_info *vpninfo)
{
char *banner, *q;
const char *p;

if (!vpninfo->banner || !(banner = malloc(strlen(vpninfo->banner)+1))) {
unsetenv("CISCO_BANNER");
return;
}
p = vpninfo->banner;
q = banner;

while (*p) {
if (*p == '%' && isxdigit((int)(unsigned char)p[1]) &&
isxdigit((int)(unsigned char)p[2])) {
*(q++) = unhex(p + 1);
p += 3;
} else
*(q++) = *(p++);
}
*q = 0;
setenv("CISCO_BANNER", banner, 1);

free(banner);
}

void set_script_env(struct openconnect_info *vpninfo)
{
char host[80];
int ret = getnameinfo(vpninfo->peer_addr, vpninfo->peer_addrlen, host,
sizeof(host), NULL, 0, NI_NUMERICHOST);
if (!ret)
setenv("VPNGATEWAY", host, 1);

set_banner(vpninfo);
unsetenv("CISCO_SPLIT_INC");
unsetenv("CISCO_SPLIT_EXC");

setenv_int("INTERNAL_IP4_MTU", vpninfo->ip_info.mtu);

if (vpninfo->ip_info.addr) {
setenv("INTERNAL_IP4_ADDRESS", vpninfo->ip_info.addr, 1);
if (vpninfo->ip_info.netmask) {
struct in_addr addr;
struct in_addr mask;

if (inet_aton(vpninfo->ip_info.addr, &addr) &&
inet_aton(vpninfo->ip_info.netmask, &mask)) {
char *netaddr;

addr.s_addr &= mask.s_addr;
netaddr = inet_ntoa(addr);

setenv("INTERNAL_IP4_NETADDR", netaddr, 1);
setenv("INTERNAL_IP4_NETMASK", vpninfo->ip_info.netmask, 1);
setenv_int("INTERNAL_IP4_NETMASKLEN", netmasklen(mask));
}
}
}
if (vpninfo->ip_info.addr6) {
setenv("INTERNAL_IP6_ADDRESS", vpninfo->ip_info.addr6, 1);
setenv("INTERNAL_IP6_NETMASK", vpninfo->ip_info.netmask6, 1);
}

if (vpninfo->ip_info.dns[0])
setenv("INTERNAL_IP4_DNS", vpninfo->ip_info.dns[0], 1);
else
unsetenv("INTERNAL_IP4_DNS");
if (vpninfo->ip_info.dns[1])
appendenv("INTERNAL_IP4_DNS", vpninfo->ip_info.dns[1]);
if (vpninfo->ip_info.dns[2])
appendenv("INTERNAL_IP4_DNS", vpninfo->ip_info.dns[2]);

if (vpninfo->ip_info.nbns[0])
setenv("INTERNAL_IP4_NBNS", vpninfo->ip_info.nbns[0], 1);
else
unsetenv("INTERNAL_IP4_NBNS");
if (vpninfo->ip_info.nbns[1])
appendenv("INTERNAL_IP4_NBNS", vpninfo->ip_info.nbns[1]);
if (vpninfo->ip_info.nbns[2])
appendenv("INTERNAL_IP4_NBNS", vpninfo->ip_info.nbns[2]);

if (vpninfo->ip_info.domain)
setenv("CISCO_DEF_DOMAIN", vpninfo->ip_info.domain, 1);
else
unsetenv("CISCO_DEF_DOMAIN");

if (vpninfo->ip_info.proxy_pac)
setenv("CISCO_PROXY_PAC", vpninfo->ip_info.proxy_pac, 1);

if (vpninfo->ip_info.split_dns) {
char *list;
int len = 0;
struct oc_split_include *dns = vpninfo->ip_info.split_dns;

while (dns) {
len += strlen(dns->route) + 1;
dns = dns->next;
}
list = malloc(len);
if (list) {
char *p = list;

dns = vpninfo->ip_info.split_dns;
while (1) {
strcpy(p, dns->route);
p += strlen(p);
dns = dns->next;
if (!dns)
break;
*(p++) = ',';
}
setenv("CISCO_SPLIT_DNS", list, 1);
free(list);
}
}
if (vpninfo->ip_info.split_includes) {
struct oc_split_include *this = vpninfo->ip_info.split_includes;
int nr_split_includes = 0;
int nr_v6_split_includes = 0;

while (this) {
process_split_xxclude(vpninfo, 1, this->route,
&nr_split_includes,
&nr_v6_split_includes);
this = this->next;
}
if (nr_split_includes)
setenv_int("CISCO_SPLIT_INC", nr_split_includes);
if (nr_v6_split_includes)
setenv_int("CISCO_IPV6_SPLIT_INC", nr_v6_split_includes);
}
if (vpninfo->ip_info.split_excludes) {
struct oc_split_include *this = vpninfo->ip_info.split_excludes;
int nr_split_excludes = 0;
int nr_v6_split_excludes = 0;

while (this) {
process_split_xxclude(vpninfo, 0, this->route,
&nr_split_excludes,
&nr_v6_split_excludes);
this = this->next;
}
if (nr_split_excludes)
setenv_int("CISCO_SPLIT_EXC", nr_split_excludes);
if (nr_v6_split_excludes)
setenv_int("CISCO_IPV6_SPLIT_EXC", nr_v6_split_excludes);
}
setenv_cstp_opts(vpninfo);
}

0 comments on commit 8f2d1a5

Please sign in to comment.