diff --git a/frontend/static/openapi.yaml b/frontend/static/openapi.yaml index d837a5d..798ffb1 100644 --- a/frontend/static/openapi.yaml +++ b/frontend/static/openapi.yaml @@ -10,7 +10,7 @@ info: license: name: Apache 2.0 url: http://www.apache.org/licenses/LICENSE-2.0.html - version: 0.15.1 + version: dev servers: - url: https://columbus.elmasy.com tags: @@ -306,6 +306,42 @@ paths: '504': description: Gateway Timeout. Upstream response takes too long. + /api/insert/{domain}: + put: + tags: + - domain + operationId: PutAPIInsert + summary: Insert domain into the database. + description: | + This endpoint technically suggest a domain to the server. + + It is required to have at least one valid DNS record for the domain to insert (eg.: `A` or `AAAA`). + The domain is sent to an underlying channel, so returns fast, but the client will not get informed about the result. + If the underlying channel is full, hangs until there is free space to send. + + This endpoint uses blacklist and rate limiter to prevent garbage and resource exhaustion + (eg.: sending invalid domain results a block for some time). + parameters: + - name: domain + in: path + description: Domain to insert. + required: true + schema: + type: string + responses: + '200': + description: OK + '400': + description: Invalid domain. + '403': + description: Client IP blocked. + '500': + description: Internal Server Error. + '502': + description: Bad Gateway. Upstream failed. + '504': + description: Gateway Timeout. Upstream response takes too long. + /api/stat: get: tags: diff --git a/server/config/config.go b/server/config/config.go index 8479ca7..2e1789b 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -6,6 +6,7 @@ import ( "runtime" "time" + "github.com/elmasy-com/elnet/blocklist" "github.com/elmasy-com/elnet/dns" "gopkg.in/yaml.v3" ) @@ -20,6 +21,10 @@ type conf struct { DNSServers []string `yaml:"DNSServers"` DomainWorker int `yaml:"DomainWorker"` DomainBuffer int `yaml:"DomainBuffer"` + InsertWorker int `yaml:"InsertWorker"` + InsertBuffer int `yaml:"InsertBuffer"` + BlocklistSize int `yaml:"BlocklistSize"` + BlockTime int `yaml:"BlockTime"` } var ( @@ -32,6 +37,11 @@ var ( DNSServers []string DomainWorker int DomainBuffer int + InsertWorker int + InsertBuffer int + BlocklistSize int + BlockTime time.Duration + Blocklist *blocklist.Blocklist ) // Parse parses the config file in path and gill the global variables. @@ -87,5 +97,31 @@ func Parse(path string) error { DomainBuffer = c.DomainBuffer + if c.InsertWorker == 0 { + c.InsertWorker = runtime.NumCPU() + } + + InsertWorker = c.InsertWorker + + if c.InsertBuffer == 0 { + c.InsertBuffer = 10000 + } + + InsertBuffer = c.InsertBuffer + + if c.BlocklistSize == 0 { + c.BlocklistSize = 1000 + } + + BlocklistSize = c.BlocklistSize + + if c.BlockTime == 0 { + c.BlockTime = 600 + } + + BlockTime = time.Duration(c.BlockTime) * time.Second + + Blocklist = blocklist.NewBlocklist(BlockTime, int64(BlocklistSize)) + return nil } diff --git a/server/route/api/insert/insert.go b/server/route/api/insert/insert.go new file mode 100644 index 0000000..bc09a16 --- /dev/null +++ b/server/route/api/insert/insert.go @@ -0,0 +1,33 @@ +package insert + +import ( + "fmt" + "net/http" + + "github.com/elmasy-com/columbus/db" + "github.com/elmasy-com/columbus/server/config" + "github.com/elmasy-com/elnet/dns" + "github.com/elmasy-com/elnet/validator" + "github.com/gin-gonic/gin" +) + +func PutApiInsert(c *gin.Context) { + + if config.Blocklist.IsBlocked(c.ClientIP()) { + c.Status(http.StatusForbidden) + return + } + + d := dns.Clean(c.Param("domain")) + + if !validator.Domain(d) { + config.Blocklist.Block(c.ClientIP()) + c.Error(fmt.Errorf("invalid domain: %s", d)) + c.Status(http.StatusBadRequest) + return + } + + db.UpdaterChan <- db.UpdateableDomain{Domain: d, Type: db.InsertNewDomain} + + c.Status(http.StatusOK) +} diff --git a/server/server.conf b/server/server.conf index 0f0f839..1928f6a 100644 --- a/server/server.conf +++ b/server/server.conf @@ -24,4 +24,10 @@ DNSServers: ["upd://8.8.8.8:53", "udp://8.8.4.4:53", "udp://1.1.1.1:53", "udp:// DomainWorker: 4 # Buffer for record updater (default: 1000) -DomainBuffer: 10000 \ No newline at end of file +DomainBuffer: 10000 + +# Size of the blocklist (default: 1000) +BlocklistSize: 1000 + +# Number of seconds to block remote IP on bad behaviour (default: 600) +BlockTime: 600 \ No newline at end of file diff --git a/server/server.go b/server/server.go index 580ced2..56299bd 100644 --- a/server/server.go +++ b/server/server.go @@ -14,6 +14,7 @@ import ( "github.com/elmasy-com/columbus/server/config" "github.com/elmasy-com/columbus/server/route/api" "github.com/elmasy-com/columbus/server/route/api/history" + "github.com/elmasy-com/columbus/server/route/api/insert" "github.com/elmasy-com/columbus/server/route/api/lookup" "github.com/elmasy-com/columbus/server/route/api/starts" "github.com/elmasy-com/columbus/server/route/api/statistics" @@ -91,6 +92,8 @@ func ServerRun() error { router.GET("/api/tools/subdomain/:fqdn", tools.ToolsSubdomainGet) router.GET("/api/tools/isvalid/:fqdn", tools.ToolsIsValidGet) + router.PUT("/api/insert/:domain", insert.PutApiInsert) + // Redirect to /search/:domain router.GET("/lookup/:domain", lookup.RedirectLookup)