feat: Added IPv6 nodes support (alpha) #84

This commit accept IPv6 nodes submission.

When user submit new public node, the server will check IP addresses
from given hostname. If host IP addresses doesn't have IPv4, it will
be recorded as "IPv6 only" node.

Probers that support IPv6 may add `IPV6_CAPABLE=true` to the `.env`
file.

Please note that this feature still experimental and may not being
merged to the main branch.
This commit is contained in:
Christian Ditaputratama 2024-09-06 00:08:59 +07:00
parent 187a7bc84a
commit 518d4b4335
No known key found for this signature in database
GPG key ID: 31D3D06D77950979
8 changed files with 67 additions and 21 deletions

View file

@ -8,6 +8,7 @@ SERVER_ENDPOINT="http://127.0.0.1:18901"
API_KEY=
ACCEPT_TOR=false
TOR_SOCKS="127.0.0.1:9050"
IPV6_CAPABLE=false
# Server Config
# #############

View file

@ -40,6 +40,7 @@ type proberClient struct {
apiKey string // prober api key
acceptTor bool // accept tor
torSOCKS string // IP:Port of tor socks
acceptIPv6 bool // accept ipv6
message string // message to include when reporting back to server
}
@ -50,6 +51,7 @@ func newProber() *proberClient {
apiKey: cfg.APIKey,
acceptTor: cfg.AcceptTor,
torSOCKS: cfg.TorSOCKS,
acceptIPv6: cfg.IPv6Capable,
}
}
@ -85,6 +87,10 @@ func (p *proberClient) SetAcceptTor(acceptTor bool) {
p.acceptTor = acceptTor
}
func (p *proberClient) SetAcceptIPv6(acceptIPv6 bool) {
p.acceptIPv6 = acceptIPv6
}
// Fetch a new job from the server, fetches node info, and sends it to the server
func (p *proberClient) Run() error {
if err := p.validateConfig(); err != nil {
@ -121,20 +127,26 @@ func (p *proberClient) validateConfig() error {
// Get monero node info to fetch from the server
func (p *proberClient) fetchJob() (monero.Node, error) {
queryParams := ""
acceptTor := 0
if p.acceptTor {
queryParams = "?accept_tor=1"
acceptTor = 1
}
acceptIPv6 := 0
if p.acceptIPv6 {
acceptIPv6 = 1
}
var node monero.Node
uri := fmt.Sprintf("%s/api/v1/job%s", p.endpoint, queryParams)
uri := fmt.Sprintf("%s/api/v1/job?accept_tor=%d&accept_ipv6=%d", p.endpoint, acceptTor, acceptIPv6)
slog.Info(fmt.Sprintf("[PROBE] Getting node from %s", uri))
req, err := http.NewRequest(http.MethodGet, uri, nil)
if err != nil {
return node, err
}
req.Header.Add(monero.ProberAPIKey, p.apiKey)
req.Header.Set("User-Agent", RPCUserAgent)

View file

@ -42,7 +42,7 @@
<section id="form-add-monero-node">
<div class="section-container text-center">
<p>Enter your Monero node information below (IPv4 host only):</p>
<p>Enter your Monero node information below (IPv6 host check is experimental):</p>
<form
class="mx-auto w-full max-w-3xl py-2"

View file

@ -24,6 +24,7 @@ type App struct {
APIKey string
AcceptTor bool
TorSOCKS string
IPv6Capable bool
}
func init() {
@ -65,4 +66,5 @@ func LoadApp() {
app.APIKey = os.Getenv("API_KEY")
app.AcceptTor, _ = strconv.ParseBool(os.Getenv("ACCEPT_TOR"))
app.TorSOCKS = os.Getenv("TOR_SOCKS")
app.IPv6Capable, _ = strconv.ParseBool(os.Getenv("IPV6_CAPABLE"))
}

View file

@ -7,7 +7,7 @@ import (
type migrateFn func(*DB) error
var dbMigrate = [...]migrateFn{v1, v2}
var dbMigrate = [...]migrateFn{v1, v2, v3}
func MigrateDb(db *DB) error {
version := getSchemaVersion(db)
@ -256,3 +256,19 @@ func v2(db *DB) error {
return nil
}
func v3(db *DB) error {
slog.Debug("[DB] Migrating database schema version 3")
// table: tbl_node
slog.Debug("[DB] Adding ipv6_only column to tbl_node")
_, err := db.Exec(`
ALTER TABLE tbl_node
ADD ipv6_only TINYINT(1) UNSIGNED NOT NULL DEFAULT '0'
AFTER cors_capable;`)
if err != nil {
return err
}
return nil
}

View file

@ -171,9 +171,10 @@ func Countries(c *fiber.Ctx) error {
// This handler should protected by `CheckProber` middleware.
func GiveJob(c *fiber.Ctx) error {
acceptTor := c.QueryInt("accept_tor", 0)
acceptIPv6 := c.QueryInt("accept_ipv6", 0)
moneroRepo := monero.New()
node, err := moneroRepo.GiveJob(acceptTor)
node, err := moneroRepo.GiveJob(acceptTor, acceptIPv6)
if err != nil {
return c.JSON(fiber.Map{
"status": "error",

View file

@ -54,6 +54,7 @@ type Node struct {
FailedCount uint `json:"failed_count,omitempty" db:"failed_count"`
LastCheckStatus types.JSONText `json:"last_check_statuses" db:"last_check_status"`
CORSCapable bool `json:"cors" db:"cors_capable"`
IPv6Only bool `json:"ipv6_only" db:"ipv6_only"`
}
// Get node from database by id
@ -197,16 +198,22 @@ func (r *moneroRepo) Add(protocol string, hostname string, port uint) error {
}
ip := ""
ipv6_only := true
if !is_tor {
hostIps, err := net.LookupIP(hostname)
if err != nil {
return err
}
hostIp := hostIps[0].To4()
if hostIp == nil {
return errors.New("Host IP is not IPv4")
for _, hostIp := range hostIps {
if hostIp.To4() != nil {
ipv6_only = false
break
}
}
hostIp := hostIps[0]
if hostIp.IsPrivate() {
return errors.New("IP address is private")
}
@ -248,7 +255,8 @@ func (r *moneroRepo) Add(protocol string, hostname string, port uint) error {
lon,
date_entered,
last_checked,
last_check_status
last_check_status,
ipv6_only
) VALUES (
?,
?,
@ -260,6 +268,7 @@ func (r *moneroRepo) Add(protocol string, hostname string, port uint) error {
?,
?,
?,
?,
?
)`,
protocol,
@ -272,7 +281,8 @@ func (r *moneroRepo) Add(protocol string, hostname string, port uint) error {
0,
time.Now().Unix(),
0,
string(statusDb))
string(statusDb),
ipv6_only)
if err != nil {
return err
}

View file

@ -108,7 +108,7 @@ func (r *moneroRepo) Logs(q QueryLogs) (FetchLogs, error) {
}
// GiveJob returns node that should be probed for the next time
func (r *moneroRepo) GiveJob(acceptTor int) (Node, error) {
func (r *moneroRepo) GiveJob(acceptTor, acceptIPv6 int) (Node, error) {
args := []interface{}{}
wq := []string{}
where := ""
@ -117,6 +117,10 @@ func (r *moneroRepo) GiveJob(acceptTor int) (Node, error) {
wq = append(wq, "is_tor = ?")
args = append(args, 0)
}
if acceptIPv6 != 1 {
wq = append(wq, "ipv6_only = ?")
args = append(args, 0)
}
if len(wq) > 0 {
where = "WHERE " + strings.Join(wq, " AND ")