syntax = "proto3"; package message; service TunnelService { // the client sends Register to the server to create a tunnel. // the server returns a stream Control to the client, the following control messages are sent through the stream. rpc Register(RegisterReq) returns (stream Control) {} // server side: write traffic to the stream, and read traffic from the stream. // client side: read traffic from the stream, and write traffic to the stream. rpc Data(stream TrafficToServer) returns (stream TrafficToClient) {} } enum Command { // Init command is sent only once as the first control message to the client. Init = 0; // Work command is sent when a user connection is established, // then the client needs to start a Data stream to receive and send data. Work = 1; } // Control is a stream used to control the tunnel. message Control { Command command = 1; oneof payload { InitPayload init = 2; WorkPayload work = 3; } } message InitPayload { string tunnel_id = 1; repeated string assigned_entrypoint = 2; } // WorkPayload is sent when the server establishes a user connection. message WorkPayload { // connection_id is the unique identifier of the connection which is assigned by the server. string connection_id = 1; } message TrafficToServer { enum Action { // start to send the traffic. // the server expects only receiving `Start` action once. Start = 0; // sending the traffic. Sending = 1; // finish sending the traffic. // the server expects only receiving `Finished` action once. Finished = 2; // the client sends the Close action to tell the server to close the user connection. // generally, when something bad happens below: // - can't dial the local upstream. Close = 3; } // when the user connects to the remote_port, the server assigns a unique_id to this connection. string connection_id = 1; // status is the status of the traffic, when the traffic streaming starts, // the first message should be the Start status without data, // then the client sends the data with the Sending status with data, // finally, after the local upstream finishes the response, the client sends the Finished status without data. Action action = 2; // data is the traffic data. bytes data = 3; } message TrafficToClient { bytes data = 1; } message RegisterReq { Tunnel tunnel = 1; } // Each tunnel is a bidirectional connection between the client and the server. // Basically, one tunnel corresponds to one http2 connection. message Tunnel { // id is the unique identifier of the tunnel, // it's assigned by the server. string id = 1; // name is the name of the tunnel. string name = 2; enum Type { TCP = 0; HTTP = 10; UDP = 20; } Type type = 3; oneof config { TCPConfig tcp = 4; HTTPConfig http = 5; UDPConfig udp = 6; } } // HttpConfig is used to tell the server how to create the http listener, // and how to route the request. // // these three fields are exclusive. message HTTPConfig { // the server's public domain is https://tunneld.dev, // you may configure a subdomain https://monitor.tunneld.dev, // then the request matches the subdomain will be forwarded to the related // tunnel. // // if domain is not empty, the server will ignore the rest of the fields. string domain = 1; // the server assigns https://{subdomain}.{domain} as the entrypoint for the // tunnel. // // if subdomain is not empty, the server will ignore the rest of the fields. string subdomain = 2; // if random_subdomain is true, the server will assign a random subdomain. bool random_subdomain = 3; // random_port is the lowest priority option, the server will assign a random port // if the remote_port is empty. // the server will listen on the remote_port to accept the http request. int32 remote_port = 4; } message TCPConfig { // if remote_port is empty, the server will assign a random port. int32 remote_port = 1; } message UDPConfig { // if remote_port is empty, the server will assign a random port. int32 remote_port = 1; }