/* $OpenBSD$ */
/*
* Copyright (c) 2015 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/utsname.h>
#include <errno.h>
#include <event.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "tmux.h"
struct tmuxproc {
const char *name;
int exit;
void (*signalcb)(int);
struct event ev_sighup;
struct event ev_sigchld;
struct event ev_sigcont;
struct event ev_sigterm;
struct event ev_sigusr1;
struct event ev_sigusr2;
struct event ev_sigwinch;
};
struct tmuxpeer {
struct tmuxproc *parent;
struct imsgbuf ibuf;
struct event event;
int flags;
#define PEER_BAD 0x1
void (*dispatchcb)(struct imsg *, void *);
void *arg;
};
static int peer_check_version(struct tmuxpeer *, struct imsg *);
static void proc_update_event(struct tmuxpeer *);
static void
proc_event_cb(__unused int fd, short events, void *arg)
{
struct tmuxpeer *peer = arg;
ssize_t n;
struct imsg imsg;
if (!(peer->flags & PEER_BAD) && (events & EV_READ)) {
if (((n = imsg_read(&peer->ibuf)) == -1 && errno != EAGAIN) ||
n == 0) {
peer->dispatchcb(NULL, peer->arg);
return;
}
for (;;) {
if ((n = imsg_get(&peer->ibuf, &imsg)) == -1) {
peer->dispatchcb(NULL, peer->arg);
return;
}
if (n == 0)
break;
log_debug("peer %p message %d", peer, imsg.hdr.type);
if (peer_check_version(peer, &imsg) != 0) {
if (imsg.fd != -1)
close(imsg.fd);
imsg_free(&imsg);
break;
}
peer->dispatchcb(&imsg, peer->arg);
imsg_free(&imsg);
}
}
if (events & EV_WRITE) {
if (msgbuf_write(&peer->ibuf.w) <= 0 && errno != EAGAIN) {
peer->dispatchcb(NULL, peer->arg);
return;
}
}
if ((peer->flags & PEER_BAD) && peer->ibuf.w.queued == 0) {
peer->dispatchcb(NULL, peer->arg);
return;
}
proc_update_event(peer);
}
static void
proc_signal_cb(int signo, __unused short events, void *arg)
{
struct tmuxproc *tp = arg;
tp->signalcb(signo);
}
static int
peer_check_version(struct tmuxpeer *peer, struct imsg *imsg)
{
int version;
version = imsg->hdr.peerid & 0xff;
if (imsg->hdr.type != MSG_VERSION && version != PROTOCOL_VERSION) {
log_debug("peer %p bad version %d", peer, version);
proc_send(peer, MSG_VERSION, -1, NULL, 0);
peer->flags |= PEER_BAD;
return (-1);
}
return (0);
}
static void
proc_update_event(struct tmuxpeer *peer)
{
short events;
event_del(&peer->event);
events = EV_READ;
if (peer->ibuf.w.queued > 0)
events |= EV_WRITE;
event_set(&peer->event, peer->ibuf.fd, events, proc_event_cb, peer);
event_add(&peer->event, NULL);
}
int
proc_send(struct tmuxpeer *peer, enum msgtype type, int fd, const void *buf,
size_t len)
{
struct imsgbuf *ibuf = &peer->ibuf;
void *vp = (void *)buf;
int retval;
if (peer->flags & PEER_BAD)
return (-1);
log_debug("sending message %d to peer %p (%zu bytes)", type, peer, len);
retval = imsg_compose(ibuf, type, PROTOCOL_VERSION, -1, fd, vp, len);
if (retval != 1)
return (-1);
proc_update_event(peer);
/*
* IPv6 virtual tunneling interface
*
* Copyright (C) 2013 secunet Security Networks AG
*
* Author:
* Steffen Klassert <steffen.klassert@secunet.com>
*
* Based on:
* net/ipv6/ip6_tunnel.c
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/module.h>
#include <linux/capability.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/sockios.h>
#include <linux/icmp.h>
#include <linux/if.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/net.h>
#include <linux/in6.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/icmpv6.h>
#include <linux/init.h>
#include <linux/route.h>
#include <linux/rtnetlink.h>
#include <linux/netfilter_ipv6.h>
#include <linux/slab.h>
#include <linux/hash.h>
#include <linux/uaccess.h>
#include <linux/atomic.h>
#include <net/icmp.h>
#include <net/ip.h>
#include <net/ip_tunnels.h>
#include <net/ipv6.h>
#include <net/ip6_route.h>
#include <net/addrconf.h>
#include <net/ip6_tunnel.h>
#include <net/xfrm.h>
#include <net/net_namespace.h>
#include <net/netns/generic.h>
#include <linux/etherdevice.h>
#define IP6_VTI_HASH_SIZE_SHIFT 5
#define IP6_VTI_HASH_SIZE (1 << IP6_VTI_HASH_SIZE_SHIFT)
static u32 HASH(const struct in6_addr *addr1, const struct in6_addr *addr2)
{
u32 hash = ipv6_addr_hash(addr1) ^ ipv6_addr_hash(addr2);
return hash_32(hash, IP6_VTI_HASH_SIZE_SHIFT);
}
static int vti6_dev_init(struct net_device *dev);
static void vti6_dev_setup(struct net_device *dev);
static struct rtnl_link_ops vti6_link_ops __read_mostly;
static unsigned int vti6_net_id __read_mostly;
struct vti6_net {
/* the vti6 tunnel fallback device */
struct net_device *fb_tnl_dev;
/* lists for storing tunnels in use */
struct ip6_tnl __rcu *tnls_r_l[IP6_VTI_HASH_SIZE];
struct ip6_tnl __rcu *tnls_wc[1];
struct ip6_tnl __rcu **tnls[2];
};
#define for_each_vti6_tunnel_rcu(start) \
for (t = rcu_dereference(start); t; t = rcu_dereference(t->next))
/**
* vti6_tnl_lookup - fetch tunnel matching the end-point addresses
* @net: network namespace
* @remote: the address of the tunnel exit-point
* @local: the address of the tunnel entry-point
*
* Return:
* tunnel matching given end-points if found,
* else fallback tunnel if its device is up,
* else %NULL
**/
static struct ip6_tnl *
vti6_tnl_lookup(struct net *net, const struct in6_addr *remote,
const struct in6_addr *local)
{
unsigned int hash = HASH(remote, local);
struct ip6_tnl *t;
struct vti6_net *ip6n = net_generic(net, vti6_net_id);
struct in6_addr any;
for_each_vti6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
if (ipv6_addr_equal(local, &t->parms.laddr) &&
ipv6_addr_equal(remote, &t->parms.raddr) &&
(t->dev->flags & IFF_UP))
return t;
}
memset(&any, 0, sizeof(any));
hash = HASH(&any,