Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions .github/workflows/proto-validate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
name: Proto validation

on:
pull_request:
types:
- opened
- synchronize
- reopened
paths:
- "**/*.proto"
- "buf.yaml"
- ".github/workflows/proto-validate.yml"

permissions:
contents: read

jobs:
validate:
runs-on: ubuntu-latest

steps:
- name: Check out repository
uses: actions/checkout@v6
with:
fetch-depth: 0

- name: Set up Buf
uses: bufbuild/buf-setup-action@v1

- name: Check formatting
run: buf format --diff --exit-code

- name: Build image
run: buf build

- name: Lint protobuf
run: buf lint

- name: Check breaking changes for v1
# Remove once new file structure is actually merged into base branch.
continue-on-error: true
run: |
buf breaking \
--against ".git#ref=${{ github.event.pull_request.base.sha }}" \
--path v1 \
--path enterprise/v1

- name: Check breaking changes for v2
# Remove when v2 compatibility is enforced.
continue-on-error: true
run: |
buf breaking \
--against ".git#ref=${{ github.event.pull_request.base.sha }}" \
--path v2 \
--path enterprise/v2
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@

See the [documentation](https://defguard.gitbook.io) for more information about the system.

## Buf CLI

This repository uses [Buf](https://buf.build/) to validate the protobuf module layout and schema quality across the versioned snapshots in `v1/`, `v2/`, `enterprise/v1/`, and `enterprise/v2/`. Imports are repo-root-relative.

- `buf build` — verify that the module and imports resolve correctly.
- `buf lint` — run the repository's Buf lint rules.
- `buf format -w` — format .proto files.

## Community and Support

Find us on Matrix: [#defguard:teonite.com](https://matrix.to/#/#defguard:teonite.com)
Expand Down
14 changes: 14 additions & 0 deletions buf.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
version: v2
modules:
- path: .
excludes:
- .direnv
lint:
use:
- BASIC
except:
- DIRECTORY_SAME_PACKAGE
- PACKAGE_DIRECTORY_MATCH
breaking:
use:
- FILE
172 changes: 172 additions & 0 deletions common/client_types.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
syntax = "proto3";
package defguard.client_types;

/*
* Shared message and enum definitions used by Defguard desktop clients (desktop app and CLI).
*
* This module exists to decouple the desktop client from any specific proxy protocol version.
* The client only needs a stable, version-independent set of types for:
* - Enrollment and device configuration (DeviceConfigResponse and its dependencies)
* - Periodic configuration polling (InstanceInfoRequest/Response)
* - Platform info reporting (ClientPlatformInfo)
*
* Both v1 and v2 proxy protocol definitions import this file and reference these types in
* their CoreRequest/CoreResponse envelopes, ensuring that a single client build can
* communicate with proxies running either protocol version without any code changes.
*
* Types that are proxy-version-specific (e.g. MFA flows, gRPC envelope messages,
* setup/certificate provisioning) are intentionally NOT included here.
*/

// Enrollment & Desktop Client activation

message EnrollmentStartRequest {
string token = 1;
}

message AdminInfo {
string name = 1;
optional string phone_number = 2;
string email = 3;
}

message InitialUserInfo {
string first_name = 1;
string last_name = 2;
string login = 3;
string email = 4;
optional string phone_number = 5;
bool is_active = 6;
repeated string device_names = 7;
bool enrolled = 8;
bool is_admin = 9;
}

message EnrollmentSettings {
// Vpn step is skippable
bool vpn_setup_optional = 1;
// Manual WireGuard setup is disabled
bool only_client_activation = 2;
// Only admins can add devices so vpn step is skipped
bool admin_device_management = 3;
// Enable Email method for MFA setup
bool smtp_configured = 4;
// MFA setup is not skippable
bool mfa_required = 5;
}

message EnrollmentStartResponse {
AdminInfo admin = 1;
InitialUserInfo user = 2;
int64 deadline_timestamp = 3;
string final_page_content = 5;
InstanceInfo instance = 7;
EnrollmentSettings settings = 8;
}

message ActivateUserRequest {
optional string phone_number = 1;
string password = 2;
optional string token = 3;
}

message NewDevice {
string name = 1;
string pubkey = 2;
optional string token = 3;
}

message ExistingDevice {
string pubkey = 1;
optional string token = 2;
}

message Device {
int64 id = 1;
string name = 2;
string pubkey = 3;
int64 user_id = 4;
int64 created_at = 5;
}

// Device configuration

enum LocationMfaMode {
LOCATION_MFA_MODE_UNSPECIFIED = 0;
LOCATION_MFA_MODE_DISABLED = 1;
LOCATION_MFA_MODE_INTERNAL = 2;
LOCATION_MFA_MODE_EXTERNAL = 3;
}

enum ServiceLocationMode {
SERVICE_LOCATION_MODE_UNSPECIFIED = 0;
SERVICE_LOCATION_MODE_DISABLED = 1;
SERVICE_LOCATION_MODE_PRELOGON = 2;
SERVICE_LOCATION_MODE_ALWAYSON = 3;
}

message DeviceConfig {
int64 network_id = 1;
string network_name = 2;
string config = 3;
string endpoint = 4;
string assigned_ip = 5;
// network pubkey
string pubkey = 6;
string allowed_ips = 7;
optional string dns = 8;
// DEPRECATED(1.5): superseded by location_mfa_mode
bool mfa_enabled = 9 [deprecated = true];
int32 keepalive_interval = 10;
optional LocationMfaMode location_mfa_mode = 11;
optional ServiceLocationMode service_location_mode = 12;
}

enum ClientTrafficPolicy {
NONE = 0;
DISABLE_ALL_TRAFFIC = 1;
FORCE_ALL_TRAFFIC = 2;
}

message InstanceInfo {
string id = 1;
string name = 2;
string url = 3;
string proxy_url = 4;
string username = 5;
bool enterprise_enabled = 6;
// DEPRECATED(1.6): superseded by client_traffic_policy
bool disable_all_traffic = 7 [deprecated = true];
optional string openid_display_name = 8;
optional ClientTrafficPolicy client_traffic_policy = 9;
}

message DeviceConfigResponse {
Device device = 1;
repeated DeviceConfig configs = 2;
InstanceInfo instance = 3;
// polling token used for further client-core communication
optional string token = 4;
}

// Configuration polling

message InstanceInfoRequest {
string token = 1;
}

message InstanceInfoResponse {
DeviceConfigResponse device_config = 1;
}

// Platform info sent as a header with every request to the proxy

message ClientPlatformInfo {
string os_family = 1;
string os_type = 2;
string version = 3;
optional string edition = 4;
optional string codename = 5;
optional string bitness = 6;
optional string architecture = 7;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
syntax = "proto3";
package enterprise.firewall;
package defguard.enterprise.firewall.v1;

// Describes target configuration of the firewall
message FirewallConfig {
Expand Down
80 changes: 80 additions & 0 deletions enterprise/v2/firewall/firewall.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
syntax = "proto3";
package defguard.enterprise.firewall.v2;

// Describes target configuration of the firewall
message FirewallConfig {
FirewallPolicy default_policy = 2;
repeated FirewallRule rules = 3;
repeated SnatBinding snat_bindings = 4;
}

enum IpVersion {
IPV4 = 0;
IPV6 = 1;
}

enum FirewallPolicy {
ALLOW = 0;
DENY = 1;
}

message FirewallRule {
int64 id = 1;
repeated IpAddress source_addrs = 2;
repeated IpAddress destination_addrs = 3;
repeated Port destination_ports = 4;
repeated Protocol protocols = 5;
FirewallPolicy verdict = 6;
optional string comment = 7;
IpVersion ip_version = 8;
}

message SnatBinding {
int64 id = 1;
repeated IpAddress source_addrs = 2;
string public_ip = 3;
optional string comment = 4;
}

// IPv4 or IPv6 address
// expected type is determined by a given FirewallRule
message IpAddress {
oneof address {
// single IP address
string ip = 1;
// range of IPs, e.g. 10.0.10.1-10.0.20.3
IpRange ip_range = 2;
// IP subnet using CIDR notation, e.g. 10.0.10.0/24
string ip_subnet = 3;
}
}

// inclusive IP range
message IpRange {
string start = 1;
string end = 2;
}

// wrapper message since `oneof` itself cannot be repeated
message Port {
oneof port {
uint32 single_port = 1;
PortRange port_range = 2;
}
}

// inclusive port range
message PortRange {
uint32 start = 1;
uint32 end = 2;
}

// Specific IDs are used to align with the standard below:
// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/in.h
enum Protocol {
// proto3 requires that first enum value must be 0
INVALID = 0;
ICMP = 1;
TCP = 6;
UDP = 17;
}
11 changes: 4 additions & 7 deletions client/client.proto → v1/client/client.proto
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
syntax = "proto3";
package client;
package defguard.client.v1;

import "google/protobuf/empty.proto";

Expand Down Expand Up @@ -79,10 +79,7 @@ message StopServiceLocationRequest {
service DesktopDaemonService {
rpc CreateInterface(CreateInterfaceRequest) returns (google.protobuf.Empty);
rpc RemoveInterface(RemoveInterfaceRequest) returns (google.protobuf.Empty);
rpc ReadInterfaceData(ReadInterfaceDataRequest)
returns (stream InterfaceData);
rpc SaveServiceLocations(SaveServiceLocationsRequest)
returns (google.protobuf.Empty);
rpc DeleteServiceLocations(DeleteServiceLocationsRequest)
returns (google.protobuf.Empty);
rpc ReadInterfaceData(ReadInterfaceDataRequest) returns (stream InterfaceData);
rpc SaveServiceLocations(SaveServiceLocationsRequest) returns (google.protobuf.Empty);
rpc DeleteServiceLocations(DeleteServiceLocationsRequest) returns (google.protobuf.Empty);
}
16 changes: 16 additions & 0 deletions v1/core/auth.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
syntax = "proto3";

package defguard.auth.v1;

service AuthService {
rpc Authenticate(AuthenticateRequest) returns (AuthenticateResponse);
}

message AuthenticateRequest {
string username = 1;
string password = 2;
}

message AuthenticateResponse {
string token = 1;
}
Loading
Loading