mirror of
				https://github.com/fluffle/goirc
				synced 2025-11-04 03:58:03 +00:00 
			
		
		
		
	Initial commit of vague hackery for a go IRCd.
This commit is contained in:
		
							parent
							
								
									83e1f9ca74
								
							
						
					
					
						commit
						b2539c0063
					
				
					 22 changed files with 1104 additions and 0 deletions
				
			
		
							
								
								
									
										17
									
								
								server/config/Makefile
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								server/config/Makefile
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,17 @@
 | 
			
		|||
# Copyright 2009 The Go Authors. All rights reserved.
 | 
			
		||||
# Use of this source code is governed by a BSD-style
 | 
			
		||||
# license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
include $(GOROOT)/src/Make.inc
 | 
			
		||||
 | 
			
		||||
TARG=irc/server/config
 | 
			
		||||
GOFILES=\
 | 
			
		||||
	config.go\
 | 
			
		||||
	port.go\
 | 
			
		||||
	oper.go\
 | 
			
		||||
	link.go\
 | 
			
		||||
	ban.go\
 | 
			
		||||
	info.go\
 | 
			
		||||
    settings.go\
 | 
			
		||||
 | 
			
		||||
include $(GOROOT)/src/Make.pkg
 | 
			
		||||
							
								
								
									
										33
									
								
								server/config/ban.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								server/config/ban.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,33 @@
 | 
			
		|||
package config
 | 
			
		||||
 | 
			
		||||
type cBan interface {
 | 
			
		||||
	Match(string) bool
 | 
			
		||||
	Reason() string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// G-Line etc; 
 | 
			
		||||
type cBanNick struct {
 | 
			
		||||
	NickMask string // nick!ident@host
 | 
			
		||||
	Reason   string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Z-Line
 | 
			
		||||
type cBanIP struct {
 | 
			
		||||
	Address string // ip (or hostname), plus optional CIDR netmask
 | 
			
		||||
	Reason  string
 | 
			
		||||
	ip		string // parsed into these
 | 
			
		||||
	cidr	int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CTCP version ban
 | 
			
		||||
type cBanVersion struct {
 | 
			
		||||
	VersionRegex string // regex to match against version reply
 | 
			
		||||
	Reason       string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Ban server from linking to network
 | 
			
		||||
type cBanServer struct {
 | 
			
		||||
	ServerMask string // matched against name of linked server
 | 
			
		||||
	Reason     string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										167
									
								
								server/config/config.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										167
									
								
								server/config/config.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,167 @@
 | 
			
		|||
package config
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"io"
 | 
			
		||||
	"os"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"scanner"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Config struct {
 | 
			
		||||
	fn string
 | 
			
		||||
	scan *scanner.Scanner
 | 
			
		||||
 | 
			
		||||
	// Ports we listen on.
 | 
			
		||||
	Ports map[int]*cPort
 | 
			
		||||
	// People with teh p0wer.
 | 
			
		||||
	Opers map[string]*cOper
 | 
			
		||||
	// Servers we link to on the network.
 | 
			
		||||
	Links map[string]*cLink
 | 
			
		||||
	// Servers/nickmasks/IPs that are unwanted.
 | 
			
		||||
	Bans []*cBan
 | 
			
		||||
 | 
			
		||||
	// Server info (name, admins, etc.)
 | 
			
		||||
	Info *cInfo
 | 
			
		||||
 | 
			
		||||
	// Server settings
 | 
			
		||||
	Settings *cSettings
 | 
			
		||||
 | 
			
		||||
	// Parse errors
 | 
			
		||||
	Errors []os.Error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type configMap  map[string]func(*Config)
 | 
			
		||||
type keywordMap map[string]func(*Config, interface{})
 | 
			
		||||
 | 
			
		||||
var configKeywords = configMap{
 | 
			
		||||
	"port": (*Config).parsePort,
 | 
			
		||||
//	"oper": (*Config).parseOper,
 | 
			
		||||
//	"link": (*Config).parseLink,
 | 
			
		||||
//	"ban":  (*Config).parseBan,
 | 
			
		||||
//	"info": (*Config).parseInfo,
 | 
			
		||||
//	"set":  (*Config).parseSettings,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func LoadConfig(filename string) *Config {
 | 
			
		||||
	conf := &Config{fn: filename}
 | 
			
		||||
	conf.initialise()
 | 
			
		||||
	if fh, err := os.Open(conf.fn, os.O_RDONLY, 0644); err == nil {
 | 
			
		||||
		conf.Parse(fh)
 | 
			
		||||
		fh.Close()
 | 
			
		||||
	} else {
 | 
			
		||||
		conf.Errors = append(conf.Errors, err)
 | 
			
		||||
	}
 | 
			
		||||
	return conf
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (conf *Config) initialise() {
 | 
			
		||||
	conf.Ports = make(map[int]*cPort)
 | 
			
		||||
	conf.Opers = make(map[string]*cOper)
 | 
			
		||||
	conf.Links = make(map[string]*cLink)
 | 
			
		||||
	conf.Bans = make([]*cBan, 0)
 | 
			
		||||
	conf.Info = &cInfo{}
 | 
			
		||||
	conf.Settings = &cSettings{}
 | 
			
		||||
	conf.Errors = make([]os.Error, 0)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (conf *Config) Rehash() {
 | 
			
		||||
	neu := LoadConfig(conf.fn)
 | 
			
		||||
	if len(neu.Errors) > 0 {
 | 
			
		||||
		conf.Errors = neu.Errors
 | 
			
		||||
	} else {
 | 
			
		||||
		conf = neu
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (conf *Config) Parse(io io.Reader) {
 | 
			
		||||
	s := &scanner.Scanner{}
 | 
			
		||||
	s.Init(io)
 | 
			
		||||
	s.Filename = conf.fn
 | 
			
		||||
	conf.scan = s
 | 
			
		||||
	tok, text := conf.next()
 | 
			
		||||
	for tok != scanner.EOF {
 | 
			
		||||
		// This external loop should only parse Config things
 | 
			
		||||
		if f, ok := configKeywords[text]; ok {
 | 
			
		||||
			f(conf)
 | 
			
		||||
		} else {
 | 
			
		||||
			conf.parseError("Invalid top-level keyword '%s'", text)
 | 
			
		||||
		}
 | 
			
		||||
		fmt.Printf("Token: '%s', type %s\n", s.TokenText(), scanner.TokenString(tok))
 | 
			
		||||
		tok, text = conf.next()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (conf *Config) parseKwBlock(dst interface{}, bt string, kw keywordMap) {
 | 
			
		||||
	if ok := conf.expect("{"); !ok {
 | 
			
		||||
		conf.parseError("Expected %s configuration block.", bt)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	tok, text := conf.next()
 | 
			
		||||
	for tok != scanner.EOF {
 | 
			
		||||
		if f, ok := kw[text]; ok {
 | 
			
		||||
			if ok = conf.expect("="); ok {
 | 
			
		||||
				f(conf, dst)
 | 
			
		||||
			}
 | 
			
		||||
		} else if text == "}" {
 | 
			
		||||
			break
 | 
			
		||||
		} else {
 | 
			
		||||
			conf.parseError("Invalid %s keyword '%s'", bt, text)
 | 
			
		||||
		}
 | 
			
		||||
		tok, text = conf.next()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var booleans = map[string]bool {
 | 
			
		||||
	"true": true,
 | 
			
		||||
	"yes": true,
 | 
			
		||||
	"on": true,
 | 
			
		||||
	"1": true,
 | 
			
		||||
	"false": false,
 | 
			
		||||
	"no": false,
 | 
			
		||||
	"off": false,
 | 
			
		||||
	"0": false,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (conf *Config) expectBool() (bool, bool) {
 | 
			
		||||
	tok, text := conf.next()
 | 
			
		||||
	if val, ok := booleans[text]; tok == scanner.Ident && ok {
 | 
			
		||||
		return val, ok
 | 
			
		||||
	}
 | 
			
		||||
	conf.parseError("Expected boolean, got '%s'", text)
 | 
			
		||||
	return false, false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (conf *Config) expectInt() (int, bool) {
 | 
			
		||||
	tok, text := conf.next()
 | 
			
		||||
	num, err := strconv.Atoi(text)
 | 
			
		||||
	if tok != scanner.Int || err != nil {
 | 
			
		||||
		conf.parseError("Expected integer, got '%s'", text)
 | 
			
		||||
		return 0, false
 | 
			
		||||
	}
 | 
			
		||||
	return num, true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (conf *Config) expect(str string) bool {
 | 
			
		||||
	_, text := conf.next()
 | 
			
		||||
	if text != str {
 | 
			
		||||
		conf.parseError("Expected '%s', got '%s'", str, text)
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (conf *Config) next() (int, string) {
 | 
			
		||||
	tok := conf.scan.Scan()
 | 
			
		||||
	text := conf.scan.TokenText()
 | 
			
		||||
	if tok == scanner.String {
 | 
			
		||||
		// drop "quotes" -> quotes
 | 
			
		||||
		text = text[1:len(text)-1]
 | 
			
		||||
	}
 | 
			
		||||
	return tok, text
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (conf *Config) parseError(err string, args ...interface{}) {
 | 
			
		||||
	err = conf.scan.Pos().String() + ": " + err
 | 
			
		||||
	conf.Errors = append(conf.Errors, os.NewError(fmt.Sprintf(err, args...)))
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										8
									
								
								server/config/info.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								server/config/info.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,8 @@
 | 
			
		|||
package config
 | 
			
		||||
 | 
			
		||||
type cInfo struct {
 | 
			
		||||
	Name, Network, Info, MOTDFile string
 | 
			
		||||
	Admins []string
 | 
			
		||||
	Numeric int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										12
									
								
								server/config/link.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								server/config/link.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,12 @@
 | 
			
		|||
package config
 | 
			
		||||
 | 
			
		||||
type cLink struct {
 | 
			
		||||
	Server      string // Server name for link
 | 
			
		||||
	Address     string // {ip,ip6,host}:port
 | 
			
		||||
	ReceivePass string // Password when server connects to us 
 | 
			
		||||
	ConnectPass string // Password when we connect to server
 | 
			
		||||
 | 
			
		||||
	// Do we use tls.Dial? or compression (no)? Do we auto-connect on start?
 | 
			
		||||
	SSL, Zip, Auto bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										16
									
								
								server/config/oper.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								server/config/oper.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,16 @@
 | 
			
		|||
package config
 | 
			
		||||
 | 
			
		||||
type cOper struct {
 | 
			
		||||
	Username, Password string
 | 
			
		||||
	HostMask []string
 | 
			
		||||
 | 
			
		||||
	// Permissions for oper
 | 
			
		||||
	CanKill, CanBan, CanNick, CanLink  bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var cOperDefaults = &cOper{
 | 
			
		||||
	HostMask: []string{"*@*"},
 | 
			
		||||
	CanKill: true, CanBan: true,
 | 
			
		||||
	CanNick: false, CanLink: false,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										86
									
								
								server/config/port.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								server/config/port.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,86 @@
 | 
			
		|||
package config
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"scanner"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type cPort struct {
 | 
			
		||||
	Port     int
 | 
			
		||||
	BindIP, Family, Class string
 | 
			
		||||
 | 
			
		||||
	// Is port a tls.Listener? Does it support compression (no)?
 | 
			
		||||
	SSL, Zip bool
 | 
			
		||||
 | 
			
		||||
	// address == "<BindIP>:<Port>"
 | 
			
		||||
	address	 string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var portKeywords = keywordMap{
 | 
			
		||||
//	"bind_ip": (*Config).parsePortBindIP,
 | 
			
		||||
//	"family": (*Config).parsePortFamily,
 | 
			
		||||
	"class": (*Config).parsePortClass,
 | 
			
		||||
	"ssl": (*Config).parsePortSSL,
 | 
			
		||||
//	"zip": (*Config).parsePortZip,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var cPortDefaults = cPort{
 | 
			
		||||
	BindIP: "", Family: "tcp", Class: "client",
 | 
			
		||||
	SSL: false, Zip: false,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func defaultPort() *cPort {
 | 
			
		||||
	p := cPortDefaults
 | 
			
		||||
	return &p
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *cPort) String() string {
 | 
			
		||||
    str := []string{fmt.Sprintf("port %d {", p.Port)}
 | 
			
		||||
	if p.BindIP != "" {
 | 
			
		||||
		str = append(str, "\tbind_ip = " + p.BindIP)
 | 
			
		||||
	}
 | 
			
		||||
	str = append(str,
 | 
			
		||||
		fmt.Sprintf("\tfamily = \"%s\"",p.Family),
 | 
			
		||||
		fmt.Sprintf("\tclass  = \"%s\"", p.Class),
 | 
			
		||||
		fmt.Sprintf("\tssl    = %t", p.SSL),
 | 
			
		||||
		fmt.Sprintf("\tzip    = %t", p.Zip),
 | 
			
		||||
		"}",
 | 
			
		||||
	)
 | 
			
		||||
	return strings.Join(str, "\n")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (conf *Config) parsePort() {
 | 
			
		||||
	port := defaultPort()
 | 
			
		||||
	portnum, ok := conf.expectInt()
 | 
			
		||||
	if !ok || portnum > 65535 || portnum < 1024 {
 | 
			
		||||
		conf.parseError("Invalid port '%s'", portnum)
 | 
			
		||||
		port = nil
 | 
			
		||||
	} else {
 | 
			
		||||
		port.Port = portnum
 | 
			
		||||
		conf.Ports[portnum] = port
 | 
			
		||||
	}
 | 
			
		||||
	if conf.scan.Peek() != '\n' {
 | 
			
		||||
		conf.parseKwBlock(port, "port", portKeywords)
 | 
			
		||||
	}
 | 
			
		||||
	fmt.Println(port.String())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (conf *Config) parsePortClass(pi interface{}) {
 | 
			
		||||
	port := pi.(*cPort)
 | 
			
		||||
	tok, text := conf.next()
 | 
			
		||||
	if tok == scanner.String && (text == "server" || text == "client") {
 | 
			
		||||
		port.Class = text
 | 
			
		||||
	} else {
 | 
			
		||||
		conf.parseError(
 | 
			
		||||
			"Port class must be \"server\" or \"client\", got '%s'", text)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (conf *Config) parsePortSSL(pi interface{}) {
 | 
			
		||||
	port := pi.(*cPort)
 | 
			
		||||
	if ssl, ok := conf.expectBool(); ok {
 | 
			
		||||
		port.SSL = ssl
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										8
									
								
								server/config/settings.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								server/config/settings.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,8 @@
 | 
			
		|||
package config
 | 
			
		||||
 | 
			
		||||
type cSettings struct {
 | 
			
		||||
	SSLKey, SSLCert, SSLCACert string
 | 
			
		||||
	MaxChans, MaxConnsPerIP int
 | 
			
		||||
	LogFile string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue