Fetching contributors…
Cannot retrieve contributors at this time
212 lines (185 sloc) 10.1 KB
# Sandstorm - Personal Cloud Sandbox
# Copyright (c) 2014 Sandstorm Development Group, Inc. and contributors
# All rights reserved.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# See the License for the specific language governing permissions and
# limitations under the License.
# This file defines Cap'n Proto interfaces for TCP/IP networking.
# The purpose of these interfaces is to implement "driver" applications -- that is, apps which
# themselves implement raw legacy network protocols (e.g. HTTP, SMTP, XMPP, etc.) and then
# re-export those protocols as a Cap'n Proto interface with meaningful separation of capabilities.
# Driver applications generally must be "approved by the Sandstorm adminsitrator" because raw
# network access can be abused in ways that harm the server as a whole. For example, an app which
# secretly sends spam via SMTP or engages in piracy via Bittorrent could harm the server's
# reputation, not just the user's.
# In practice, a driver app is technically just a regular application that makes a Powerbox request
# for raw network access (represented by the interfaces defined in this file). Only the server
# administrator normally possesses these capabilities, therefore only the administartor can
# normally authorize such apps.
# Of course, a regular user could run a driver app and connect it to fake networking capabilities,
# e.g. for the purpose of testing, or for use over a fake IP network that only connects to other
# Sandstorm apps.
# For simplicity in porting legacy apps, sandstorm-http-bridge can optionally be configured to
# act as an IP proxy, allowing legacy apps to transparently use IP networking via the standard
# socket API.
$import "/capnp/c++.capnp".namespace("sandstorm");
using Util = import "util.capnp";
using SystemPersistent = import "supervisor.capnp".SystemPersistent;
interface IpNetwork @0xa982576b7a2a2040 {
# Capability to connect or send messages to arbitrary destinations on an IP network.
# A driver app can request this from the Powerbox in order to request "full outbound network
# access". The IpNetwork capability is a dangerous capability that should only be granted to
# trusted drivers. Only the Sandstorm server administrator is likely to possess this capability.
struct PowerboxTag {
# Tag to be used in a `PowerboxDescriptor` to describe an `IpNetwork`.
encryption @0 :Encryption;
# The encryption scheme, if any, on top of which the `IpNetwork` layers its connections
# and messages.
struct Encryption @0xe2d94cf90fe4078d {
# Describes an encryption scheme.
# Capabilities derived from an `IpNetwork` may use this struct in their own powerbox
# descriptors, either in an explicit `PowerboxTag.encryption` field, like here with
# `IpNetwork`, or in an independent powerbox tag, marked by this struct's type ID.
union {
none @0 :Void;
# No encryption.
tls @1 :Void;
# Transport Layer Security, using a standard set of certificates.
getRemoteHost @0 (address :IpAddress) -> (host :IpRemoteHost);
# Get the remote host corresponding to the given address.
getRemoteHostByName @1 (address :Text) -> (host :IpRemoteHost);
# Like `getRemoteHost()` but parse the address from text and perform a DNS lookup if necessary.
# Textual representations of IP addresses will also be accepted.
struct IpAddress {
# An IPv6 address.
# IPv4 addresses must be represented using IPv4-mapped IPv6 addresses.
lower64 @0 :UInt64;
upper64 @1 :UInt64;
# Bits of the IPv6 address. Since IP is a big-endian spec, the "lower" bits are on the right, and
# the "upper" bits on the left. E.g., if the address is "1:2:3:4:5:6:7:8", then the lower 64 bits
# are "5:6:7:8" or 0x0005000600070008 while the upper 64 bits are "1:2:3:4" or 0x0001000200030004.
# Note that for an IPv4 address, according to the standard IPv4-mapped IPv6 address rules, you
# would use code like this:
# uint32 ipv4 = (octet[0] << 24) | (octet[1] << 16) | (octet[2] << 8) | octet[3];
# dest.setLower64(0x0000FFFF00000000 | ipv4);
# dest.setUpper64(0);
interface IpInterface @0xe32c506ee93ed6fa {
# Capability to accept connections / messages on a particular network interface.
# In practice this could represent a single physical network interface, a single local IP
# address, or "all interfaces" (i.e.
# A driver app can request this from the Powerbox in order to request "full inbound network
# access", i.e. permission to open and listen on any port. The IpInterface capability is a
# dangerous capability that should only be granted to trusted drivers. Only the Sandstorm server
# administrator is likely to possess this capability.
listenTcp @0 (portNum :UInt16, port :TcpPort) -> (handle :Util.Handle);
# Binds `port` to the given TCP port number, so that it will receive any incoming TCP connections
# to the port.
listenUdp @1 (portNum :UInt16, port :UdpPort) -> (handle :Util.Handle);
# Binds `port` to the given UDP port number, so that it will receive any incoming UDP datagrams
# sent to the port.
interface IpRemoteHost @0x905dd76b298b3130 {
# Capability to connect / send messages to a particular remote host accessed over an IP network.
# A driver app can request this form the Powerbox in order to request "permission to connect to
# arbitrary ports on a particular host". While not as dangerous as IpNetwork, this is still a
# sensitive capability, as connecting to e.g. Google could allow an app to send mass quantities
# of spam (while perhaps claiming that it is just updating your calendar, or something).
# Only request an `IpRemoteHost` capability if you need to be able to connect to multiple ports
# on the host. If you only need to connect to one port, request `TcpPort` or `UdpPort` instead.
# This way the user can more easily understand what is being requested and can more easily
# reroute when desired.
getTcpPort @0 (portNum :UInt16) -> (port :TcpPort);
getUdpPort @1 (portNum :UInt16) -> (port :UdpPort);
interface TcpPort @0xeab20e1af07806b4 {
# Capability to connect to a remote network port.
# An application may request a TcpPort from the Powerbox in order to request permission to
# form a TCP connection to an arbitrary address.
# An application may offer a TcpPort to the Powerbox in order to implement a TCP server and
# request that it be mapped to an address.
# While intended to represent a real IP address/port, this interface may in fact be offered and
# received between two apps through the Powerbox, in which case there is in fact no IP address
# assigned.
connect @0 (downstream :Util.ByteStream) -> (upstream :Util.ByteStream);
# Open a new byte stream connection. The callee sends bytes to the caller via `downstream`, while
# the caller sends bytes to the callee via `upstream`. Notice that the caller may start sending
# bytes via pipelining immediately.
interface UdpPort @0xc6212e1217d001ce {
# Like `TcpPort` but for datagrams.
send @0 (message :Data, returnPort :UdpPort);
# Send a datagram.
# As always with UDP, successful return does not indicate successful delivery. On the receiving
# end, a message may be delivered multiple times and/or may be truncated. It is the app's
# responsibility to deal with ACKs, timeouts, message ordering, de-duplification, and data
# integrity.
# `returnPort` may be used to send a direct reply. On the sending side, if the datagram is sent as
# a real UDP packet, `returnPort` will be bound to an ephemeral port for a short time to receive
# this reply. If `returnPort` is already bound to a port (either explicitly, or because it was
# used in a previous `sendDatagram` call), then IP bridge implementation will reuse that binding
# rather than allocate a new one. Therefore, frequently sending datagrams with the same
# `returnPort` should have the effect of keeping the real IP address/port constant (this is
# analogous to how NATs typically handle UDP traffic).
# TODO(someday): Cap'n Proto should support marking methods as "fast-but-unreliable", with all
# the properties of UDP. Then, this method should be marked as such.
struct IpPortPowerboxMetadata {
# When making a Powerbox request for or offer of a `TcpPort` or `UdpPort`, this metadata may be
# specified to refine the request / offer.
# TODO(soon): This is currently more of a concept, as we have not yet decided how "metadata"
# should be attached to Powerbox requests or offers.
preferredPortNum @0 :UInt16;
# The "standard" port number for the service being offered / requested.
# For Powerbox requests, this is used to fill in the port number of the remote service. The
# user then only needs to fill in a hostname or IP. The user may override the port if desired.
# For Powerbox offers, this is used to specify the port to which the service ought to be bound,
# although the user may override it.
preferredHost @1 :Text;
# If non-empty, contains the port's expected/preferred host name. Like preferredPortNum, this is
# used to prefill forms, but the user may override. A textual representation of an IP address
# (v4 or v6) is also allowed here.
# If possible, design your app so that the powerbox interaction is the point where the hostname
# is specified in the first place. For example, if your app asks the user to specify a host to
# connect to, and then immediately makes a powerbox request for that host, consider instead not
# asking the user for a hostname at all and instead making the Powerbox request right off and
# letting the user specify the hostname there.
interface PersistentIpNetwork extends (IpNetwork, SystemPersistent) {}
interface PersistentIpInterface extends (IpInterface, SystemPersistent) {}