Skip to content

Commit

Permalink
Move set_script_env() to script.c
Browse files Browse the repository at this point in the history
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.