mirror of
https://github.com/Li4n0/revsuit.git
synced 2026-09-27 00:51:55 +08:00
feat: complete basic functions
Support http,dns and mysql connection. Support custom http, dns response. Support dns rebinding. Support mysql load local files and jdbc deserialize exploit.
This commit is contained in:
@@ -0,0 +1,263 @@
|
||||
package newdns
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Zone describes a single authoritative DNS zone.
|
||||
type Zone struct {
|
||||
// The FQDN of the zone e.g. "example.com.".
|
||||
Name string
|
||||
|
||||
// The FQDN of the master mame server responsible for this zone. The FQDN
|
||||
// must be returned as A and AAAA record by the parent zone.
|
||||
MasterNameServer string
|
||||
|
||||
// A list of FQDNs to all authoritative name servers for this zone. The
|
||||
// FQDNs must be returned as A and AAAA records by the parent zone. It is
|
||||
// required to announce at least two distinct name servers per zone.
|
||||
AllNameServers []string
|
||||
|
||||
// The email address of the administrator e.g. "[email protected]".
|
||||
//
|
||||
// Default: "hostmaster@NAME".
|
||||
AdminEmail string
|
||||
|
||||
// The refresh interval.
|
||||
//
|
||||
// Default: 6h.
|
||||
Refresh time.Duration
|
||||
|
||||
// The retry interval for the zone.
|
||||
//
|
||||
// Default: 1h.
|
||||
Retry time.Duration
|
||||
|
||||
// The expiration interval of the zone.
|
||||
//
|
||||
// Default: 72h.
|
||||
Expire time.Duration
|
||||
|
||||
// The TTL for the SOA record.
|
||||
//
|
||||
// Default: 15m.
|
||||
SOATTL time.Duration
|
||||
|
||||
// The TTL for NS records.
|
||||
//
|
||||
// Default: 48h.
|
||||
NSTTL time.Duration
|
||||
|
||||
// The minimum TTL for all records. Either this value, or the SOATTL if lower,
|
||||
// is used to determine the "negative caching TTL" which is the duration
|
||||
// caches are allowed to cache missing records (NXDOMAIN).
|
||||
//
|
||||
// Default: 5min.
|
||||
MinTTL time.Duration
|
||||
|
||||
// The handler that responds to requests for this zone. The returned sets
|
||||
// must not be altered going forward.
|
||||
Handler func(name, remoteAddr string) ([]Set, error)
|
||||
}
|
||||
|
||||
// Validate will validate the zone and ensure the documented defaults.
|
||||
func (z *Zone) Validate() error {
|
||||
// check name
|
||||
if !IsDomain(z.Name, true) {
|
||||
return errors.Errorf("name not fully qualified: %s", z.Name)
|
||||
}
|
||||
|
||||
// check master name server
|
||||
if !IsDomain(z.MasterNameServer, true) {
|
||||
return errors.Errorf("master server not full qualified: %s", z.MasterNameServer)
|
||||
}
|
||||
|
||||
// check name server count
|
||||
if len(z.AllNameServers) < 1 {
|
||||
return errors.Errorf("missing name servers")
|
||||
}
|
||||
|
||||
// check name servers
|
||||
var includesMaster bool
|
||||
for _, ns := range z.AllNameServers {
|
||||
if !IsDomain(ns, true) {
|
||||
return errors.Errorf("name server not fully qualified: %s", ns)
|
||||
}
|
||||
|
||||
if ns == z.MasterNameServer {
|
||||
includesMaster = true
|
||||
}
|
||||
}
|
||||
|
||||
// check master inclusion
|
||||
if !includesMaster {
|
||||
return errors.Errorf("master name server not listed as name server: %s", z.MasterNameServer)
|
||||
}
|
||||
|
||||
// set default admin email
|
||||
if z.AdminEmail == "" {
|
||||
z.AdminEmail = fmt.Sprintf("hostmaster@%s", z.Name)
|
||||
}
|
||||
|
||||
// check admin email
|
||||
if !IsDomain(emailToDomain(z.AdminEmail), true) {
|
||||
return errors.Errorf("admin email cannot be converted to a domain name: %s", z.AdminEmail)
|
||||
}
|
||||
|
||||
// set default refresh
|
||||
if z.Refresh == 0 {
|
||||
z.Refresh = 6 * time.Hour
|
||||
}
|
||||
|
||||
// set default retry
|
||||
if z.Retry == 0 {
|
||||
z.Retry = time.Hour
|
||||
}
|
||||
|
||||
// set default expire
|
||||
if z.Expire == 0 {
|
||||
z.Expire = 72 * time.Hour
|
||||
}
|
||||
|
||||
// set default SOA TTL
|
||||
if z.SOATTL == 0 {
|
||||
z.SOATTL = 15 * time.Minute
|
||||
}
|
||||
|
||||
// set default NS TTL
|
||||
if z.NSTTL == 0 {
|
||||
z.NSTTL = 48 * time.Hour
|
||||
}
|
||||
|
||||
// set default min TTL
|
||||
if z.MinTTL == 0 {
|
||||
z.MinTTL = 5 * time.Minute
|
||||
}
|
||||
|
||||
// check retry
|
||||
if z.Retry >= z.Refresh {
|
||||
return errors.Errorf("retry must be less than refresh: %d", z.Retry)
|
||||
}
|
||||
|
||||
// check expire
|
||||
if z.Expire < z.Refresh+z.Retry {
|
||||
return errors.Errorf("expire must be bigger than the sum of refresh and retry: %d", z.Expire)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Lookup will lookup the specified name in the zone and return results for the
|
||||
// specified record types. If no results are returned, the second return value
|
||||
// indicates if there are other results for the specified name.
|
||||
func (z *Zone) Lookup(name, remoteAddr string, needle ...Type) ([]Set, bool, error) {
|
||||
// check name
|
||||
if !IsDomain(name, true) {
|
||||
return nil, false, errors.Errorf("invalid name: %s", name)
|
||||
}
|
||||
|
||||
// normalize name
|
||||
name = NormalizeDomain(name, true, false, false)
|
||||
|
||||
// check name
|
||||
if !InZone(z.Name, name) {
|
||||
return nil, false, errors.Errorf("name does not belong to zone: %s", name)
|
||||
}
|
||||
|
||||
// prepare result
|
||||
var result []Set
|
||||
|
||||
for i := 0; ; i++ {
|
||||
// get sets
|
||||
sets, err := z.Handler(TrimZone(z.Name, name),remoteAddr)
|
||||
if err != nil {
|
||||
return nil, false, errors.Wrap(err, "zone handler error")
|
||||
}
|
||||
|
||||
// return immediately if initial set is empty
|
||||
if i == 0 && len(sets) == 0 {
|
||||
return nil, false, nil
|
||||
}
|
||||
|
||||
// prepare counters
|
||||
counters := map[Type]int{
|
||||
A: 0,
|
||||
AAAA: 0,
|
||||
CNAME: 0,
|
||||
MX: 0,
|
||||
TXT: 0,
|
||||
}
|
||||
|
||||
// validate sets
|
||||
for _, set := range sets {
|
||||
// validate set
|
||||
err = set.Validate()
|
||||
if err != nil {
|
||||
return nil, false, errors.Wrap(err, "invalid set")
|
||||
}
|
||||
|
||||
// check relationship
|
||||
if !InZone(z.Name, set.Name) {
|
||||
return nil, false, errors.Errorf("set does not belong to zone: %s", set.Name)
|
||||
}
|
||||
|
||||
// increment counter
|
||||
counters[set.Type]++
|
||||
}
|
||||
|
||||
// check counters
|
||||
for _, counter := range counters {
|
||||
if counter > 1 {
|
||||
return nil, false, errors.New("multiple sets for same type")
|
||||
}
|
||||
}
|
||||
|
||||
// check apex CNAME
|
||||
if counters[CNAME] > 0 && name == z.Name {
|
||||
return nil, false, errors.Errorf("invalid CNAME set at apex: %s", name)
|
||||
}
|
||||
|
||||
// check CNAME is stand-alone
|
||||
if counters[CNAME] > 0 && (len(sets) > 1) {
|
||||
return nil, false, errors.Errorf("other sets with CNAME set: %s", name)
|
||||
}
|
||||
|
||||
// check if CNAME and query is not CNAME
|
||||
if counters[CNAME] > 0 && !typeInList(needle, CNAME) {
|
||||
// add set to result
|
||||
result = append(result, sets[0])
|
||||
|
||||
// get normalized address
|
||||
address := NormalizeDomain(sets[0].Records[0].Address, true, false, false)
|
||||
|
||||
// continue lookup with CNAME address if address is in zone
|
||||
if InZone(z.Name, address) {
|
||||
name = address
|
||||
continue
|
||||
}
|
||||
|
||||
return result, false, nil
|
||||
}
|
||||
|
||||
// add matching set
|
||||
for _, set := range sets {
|
||||
if typeInList(needle, set.Type) {
|
||||
// add set to result
|
||||
result = append(result, set)
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// return if there are not matches, but indicate that there are sets
|
||||
// available for other types
|
||||
if len(result) == 0 {
|
||||
return nil, true, nil
|
||||
}
|
||||
|
||||
return result, false, nil
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user