Skip to content

feat(cryptostorm): add WireGuard and OpenVPN provider support#3164

Open
mpatton125 wants to merge 5 commits into
passteque:masterfrom
mpatton125:claude/crazy-brahmagupta
Open

feat(cryptostorm): add WireGuard and OpenVPN provider support#3164
mpatton125 wants to merge 5 commits into
passteque:masterfrom
mpatton125:claude/crazy-brahmagupta

Conversation

@mpatton125

@mpatton125 mpatton125 commented Feb 26, 2026

Copy link
Copy Markdown

Description

  • Add cryptostorm.is as a new VPN provider with both WireGuard and OpenVPN support
  • Both protocols use port 443 (TCP/UDP), server data fetched from cryptostorm JSON API
  • Includes port forwarding support via cryptostorm's internal forwarding server

Issue

Fix #3112


🤖 Generated with Claude Code <--- Full disclosure

@qdm12 qdm12 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Big hallucination on the updating servers code. this needs to be fixed somehow, or this PR won't be accepted
  • Port forwarding: I need a human to check the information returned from the port forwarding endpoint when connected
  • When above is done, I need a human to verify openvpn tcp, udp, wireguard and port forwarding all work fine.

// their publicly available node list. If the upstream format changes,
// update the nodeData struct and parsing logic accordingly.
func fetchAPI(ctx context.Context, client *http.Client) (data []nodeData, err error) {
const url = "https://cryptostorm.is/wireguard/nodes.json"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is no json API, this url is the same as https://cryptostorm.is/wireguard. This returns html, not json and this will fail

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now scraping endpoint data from https://cryptostorm.is/wireguard.

func (p *Provider) GetConnection(selection settings.ServerSelection, ipv6Supported bool) (
connection models.Connection, err error,
) {
defaults := utils.NewConnectionDefaults(443, 443, 443) //nolint:mnd

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please double check openvpn udp tcp and wireguard all work with those 443 ports.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definitely both work with 443 - provider says they accept OpenVPN and Wireguard connections on any port (1-65535).

Comment thread internal/provider/cryptostorm/openvpnconf.go Outdated
Comment thread internal/storage/servers.json Outdated
}
]
},
"cryptostorm": {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that was not obtained from the code in the updater, so it most likely pure hallucination; fix the updater and revert these changes.

Comment thread Dockerfile Outdated
// If the port is already forwarded (e.g. from a previous session) it will appear in
// the list regardless of whether the POST succeeded, so we treat that as success.
// Valid port range is 30000–65535.
// See: https://cryptostorm.is/port_forwarding

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

404 not found, possible hallucination? please fix

it's https://cryptostorm.is/portfwd

postBody = "port=" + strconv.FormatUint(uint64(objects.ListeningPort), 10)
}

pfURL := "http://" + cryptostormPFServer + "/fwd"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add a comment for IPv6 it's http://[2001:db8::7]/fwd - that will be used later.

postBody = "port=" + strconv.FormatUint(uint64(objects.ListeningPort), 10)
}

pfURL := "http://" + cryptostormPFServer + "/fwd"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mpatton125 can you check what http://10.31.33.7/fwd returns when you are connected to the VPN? To confirm what the AI wrote is correct


const base, bitSize = 10, 16
for _, match := range matches {
portUint64, err := strconv.ParseUint(match[1], base, bitSize)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can there be multiple ports? 🤔

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes this provider allows multiple port forwards, per endpoint.

@qdm12 qdm12 Mar 10, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a maximum limit of ports forwarded??

Let's wait for #3208 to be merged, then this can use the new setting field PortsCount

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rebase on upstream master, which supports multiple ports. What's the number of ports limit?

Comment thread internal/provider/utils/portforward.go Outdated
Comment on lines +28 to +30
// ListeningPort is the port to request from the provider, used by Cryptostorm.
// A value of 0 means let the provider assign a port.
ListeningPort uint16

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mpatton125 please confirm if http://10.31.33.7/fwd tells you you can specify a port field, and if that port field can be set to 0 to let cryptostorm assign you a random port.

If this is the case:

  1. use the VPN_PORT_FORWARDING_LISTENING_PORT value to set this. If this one is not set, try to read it from /gluetun/portforward/cryptostorm.json. If this file does not exist, leave the ListeningPort field to 0 to let cryptostorm decide.
  2. in all cases, persist the resulting port(s) to /gluetun/portforward/cryptostorm.json

And also:

  • add a comment in internal/provider/privateinternetaccess/provider.go next to const jsonPortForwardPath = "/gluetun/piaportforward.json" saying TODO v4: move to /gluetun/portforward/privateinternetaccess.json
  • update the comment for the settings field VPN_PORT_FORWARDING_LISTENING_PORT and make sure it runs a no-op in case the forwarded port is already the value specified in VPN_PORT_FORWARDING_LISTENING_PORT

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes you can specify a port at that URL, from 30000-65535. No, it can't be 0 for a random port - user must specify.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it, let's wait for #3208

note for future:

we'll then use VPN_PORT_FORWARDING_LISTENING_PORTS=8000,8001 to specify ports you want. We should then change func (p *PortForwarding) setDefaults() to func (p *PortForwarding) setDefaults(vpnProvider string) and set, if the vpnProvider is cryptostorm only, p.PortsCount = gosettings.DefaultComparable(p.PortsCount, len(p.ListeningPorts))

@qdm12 qdm12 marked this pull request as draft March 7, 2026 05:21
@qdm12 qdm12 force-pushed the master branch 2 times, most recently from 2c06921 to 9a5995f Compare March 16, 2026 13:48
@mpatton125 mpatton125 marked this pull request as ready for review April 15, 2026 00:49
@mpatton125 mpatton125 requested a review from qdm12 April 15, 2026 22:23
@mpatton125 mpatton125 force-pushed the claude/crazy-brahmagupta branch from cd21991 to e79b2df Compare April 23, 2026 00:02
@qdm12 qdm12 force-pushed the master branch 4 times, most recently from 40f126b to 44d5104 Compare May 3, 2026 04:29
Comment on lines +42 to +43
// is its default as well. For Cryptostorm, this also specifies the
// port to request for forwarding (must be between 30000 and 65535).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(no action for now) to be updated after #3208 is merged and this branch gets updated with master.

Comment thread internal/portforward/service/start.go Outdated
CanPortForward: s.settings.CanPortForward,
Username: s.settings.Username,
Password: s.settings.Password,
ListeningPort: s.settings.ListeningPort,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(no action for now) to be updated after #3208 is merged - add comment stating this is only used for cryptostorm to request specific ports, for other providers, it's only used to redirect ports

Comment thread internal/portforward/service/start.go Outdated
}

err = s.onNewPorts(ctx, ports)
if s.settings.ListeningPort != 0 && port != s.settings.ListeningPort {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(no action for now) to be updated after #3208 is merged - update to check by index ports[i] != s.settings.ListeningPorts[i] and also we should ensure both slices are sorted

type nodeData struct {
Location string // e.g. "Canada - Montreal", "Austria", "US - Texas - Dallas"
Hostname string // e.g. "austria.cstorm.is"
WgPubKey string // WireGuard public key

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit unneeded

Suggested change
WgPubKey string // WireGuard public key
WgPubKey string

return nil, nil, fmt.Errorf("fetching HTML: %w", err)
}

return parseHTML(rootNode)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return parseHTML(rootNode)
nodes, warnings, err = parseHTML(rootNode)
if err != nil {
return nil, nil, fmt.Errorf("parsing HTML: %w", err)
}
return nodes, warnings, nil

// Allow explicit endpoint IP override.
switch selection.VPN {
case vpn.OpenVPN:
if t := selection.OpenVPN.EndpointIP; t.IsValid() && !t.IsUnspecified() {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why t??? change to ip. same below


const base, bitSize = 10, 16
for _, match := range matches {
portUint64, err := strconv.ParseUint(match[1], base, bitSize)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rebase on upstream master, which supports multiple ports. What's the number of ports limit?

common.Fetcher
}

func New(storage common.Storage, randSource rand.Source,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rebase on upstream master, randSource is no longer needed.

client *http.Client, updaterWarner common.Warner,
parallelResolver common.ParallelResolver,
) *Provider {
const jsonPortForwardPath = "/gluetun/portforward/cryptostorm.json"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit rename to portForwardPath

PortsCount uint16
// ListeningPorts are the user-specified ports. For Cryptostorm, ListeningPorts[0]
// is the port to request from the forwarding server (must be 30000–65535).
// A nil or [0] value means fall back to the persisted port.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can there be multiple ports requested?

Michael Patton and others added 2 commits June 29, 2026 10:37
…and IPv6

Implements Cryptostorm as a gluetun VPN provider supporting WireGuard and
OpenVPN protocols, dual-stack IPv4/IPv6 port forwarding via HTTP to the
Cryptostorm forwarding servers, and a server updater that fetches node data
from cryptostorm.is/wireguard.

Key changes:
- Provider struct using ConnectionPicker (aligned with master's pattern)
- Port forwarding with IPv4 (10.31.33.7) and IPv6 (2001:db8::7) endpoints
- Updater with simplified client-only struct (no parallelResolver/warner)
- DNS resolution via net.DefaultResolver in the updater
- setDefaults(vpnProvider) signature to set PortsCount default for Cryptostorm
- Self-redirect guard in portforward service onNewPorts()
- ListeningPorts support in PortForwardObjects

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…s module

When a provider's JSON file is not yet in the embedded gluetun-servers module
(e.g. newly added providers like Cryptostorm), start with an empty server list
instead of panicking. The updater will populate servers at runtime.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Michael Patton and others added 2 commits June 29, 2026 11:04
…errors

common.ErrPortForwardNotSupported and common.ErrHTTPStatusCodeNotOK were
removed from master. Replace with inline fmt.Errorf calls matching the
pattern used by other providers.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@mpatton125 mpatton125 requested a review from qdm12 June 29, 2026 01:11
Without a version, checkVersions() discards any on-disk data for the
provider because version 0 never matches the file's version 1.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature request: cryptostorm.is VPN

2 participants