Exemple #1
0
func ConfReload() {
	// Do not panic!
	defer func() {
		if r := recover(); r != nil {
			log.Errorf("paniced when reloading config %s, recovered.", config_file)
			log.Errorf("panic: %s", r)
		}
	}()
	log.Warn("Reloading config")
	content, err := ioutil.ReadFile(config_file)
	if err != nil {
		log.Errorf("unable to reload config %s: %s", config_file, err.Error())
		return
	}
	prev_listen := config.Listen_addr
	config_lock.Lock()
	err = yaml.Unmarshal(content, &config)
	if err != nil {
		log.Errorf("error when parsing config file %s: %s", config_file, err.Error())
		return
	}
	validateConfig()
	config_lock.Unlock()
	log.Info("config reloaded.")
	if config.Listen_addr != prev_listen {
		log.Warnf("config reload will not reopen server socket, thus no effect on listen address")
	}
	log.Infof("%d upstream server(s) found", len(config.Upstream))
}
Exemple #2
0
func RejectHandler(conn *WrapedSocket, initial_pkt *mcproto.MCHandShake, e *mcchat.ChatMsg) {
	if initial_pkt.NextState == 1 {
		conn.Infof("ping packet")
		pkt, err := mcproto.ReadPacket(conn)
		if err != nil {
			conn.Errorf("Error when reading status request: %s", err.Error())
			conn.Close()
			return
		}
		if !pkt.IsStatusRequest() {
			conn.Errorf("Invalid protocol: no status request.")
			conn.Close()
			return
		}
		conn.Debugf("status: request")
		resp := new(mcproto.MCStatusResponse)
		resp.Description = e
		resp.Version.Name = "minegate"
		resp.Version.Protocol = 0
		resp_pkt, err := resp.ToRawPacket()
		if err != nil {
			conn.Errorf("Unable to make packet: %s", err.Error())
			conn.Close()
			return
		}
		_, err = conn.Write(resp_pkt.ToBytes())
		if err != nil {
			log.Errorf("Unable to write response: %s", err.Error())
			conn.Close()
			return
		}
		pkt, err = mcproto.ReadPacket(conn)
		if err != nil {
			if err != io.EOF {
				log.Errorf("Unable to read packet: %s", err.Error())
			}
			conn.Close()
			return
		}
		if !pkt.IsStatusPing() {
			log.Error("Invalid protocol: no status ping.")
			conn.Close()
			return
		}
		conn.Write(pkt.ToBytes()) // Don't care now.
	} else {
		log.Info("login packet")
		kick_pkt := (*mcproto.MCKick)(e)
		raw_pkt, err := kick_pkt.ToRawPacket()
		if err != nil {
			log.Errorf("Unable to make packet: %s", err.Error())
			conn.Close()
			return
		}
		// Don't care now
		conn.Write(raw_pkt.ToBytes())
	}
	conn.Close()
	return
}
Exemple #3
0
func Run() {
	PreLoadConfig()
	confInit()
	PostLoadConfig()
	runtime.GOMAXPROCS(runtime.NumCPU())
	log.Infof("MineGate %s started.", version_full)
	go ServerSocket()
	sig := make(chan os.Signal, 1)
	signal.Notify(sig, syscall.SIGHUP, syscall.SIGUSR1)
	for {
		cur := <-sig
		switch cur {
		case syscall.SIGHUP:
			log.Warn("SIGHUP caught, reloading config...")
			PreLoadConfig()
			ConfReload()
			PostLoadConfig()
		case syscall.SIGUSR1:
			log.Warn("SIGUSR1 caught, rotating log...")
			log.Rotate()
		default:
			log.Errorf("Trapped unexpected signal: %s", cur.String())
			continue
		}
	}
}
Exemple #4
0
func (upstream *Upstream) Validate() (valid bool) {
	var host, port string
	host, port, err := net.SplitHostPort(upstream.Server)
	if err != nil {
		server := upstream.Server + ":25565"
		if host, port, err = net.SplitHostPort(server); err != nil {
			log.Error("Invalid upstream server: " + upstream.Server)
			return false
		}
		log.Infof("no port information found in %s, assume 25565", upstream.Server)
		upstream.Server = server
	}
	p, err := strconv.ParseUint(port, 10, 16)
	if err != nil {
		log.Errorf("Invalid port %s: %s", port, err.Error())
		return false
	}
	host = strings.ToLower(host)
	if !CheckHost(host) {
		log.Error("Invalid upstream host: " + host)
		return false
	}
	upstream.Server = net.JoinHostPort(host, fmt.Sprintf("%d", p))
	upstream.Pattern = strings.ToLower(upstream.Pattern)
	if !CheckPattern(upstream.Pattern) {
		log.Error("Invalid pattern: " + upstream.Pattern)
		return false
	}
	if upstream.ErrorMsg.Text == "" {
		log.Warnf("Empty error text for %s, use default string", upstream.Server)
		upstream.ErrorMsg.Text = "Connection failed to " + upstream.Server
	}
	upstream.ChatMsg = ToChatMsg(&upstream.ErrorMsg)
	return true
}
Exemple #5
0
func (upstream *Upstream) GetExtra(path string) (val interface{}, err error) {
	defer func() {
		if r := recover(); r != nil {
			log.Errorf("Recovered panic: upstream.GetExtra(%s), err=%+v", path, r)
			log.Debugf("Upstream: %+v", upstream)
			val = nil
			err = errors.New("panic when getting config.")
			return
		}
	}()
	paths := strings.Split(path, ".")
	cur := reflect.ValueOf(upstream.Extras)
	// ROOT can't be an array, so assume no config path starts with #
	for _, path := range paths {
		index := strings.Split(path, "#")
		prefix, index := index[0], index[1:]
		if cur.Kind() != reflect.Map {
			log.Warnf("upstream.GetExtra(%s): unable to fetch key %s, not a map.", path, prefix)
			return nil, fmt.Errorf("index key on non-map type")
		}
		cur = reflect.ValueOf(cur.MapIndex(reflect.ValueOf(prefix)).Interface())
		for _, idx := range index {
			i, err := strconv.ParseInt(idx, 0, 0)
			if err != nil {
				log.Errorf("upstream.GetExtra(%s): unable to parse %s: %s", path, idx, err.Error())
				return nil, fmt.Errorf("Unable to parse %s: %s", idx, err.Error())
			}
			if cur.Kind() != reflect.Slice {
				log.Warnf("upstream.GetExtra(%s): unable to index value, not a slice", path)
				return nil, errors.New("Unable to index value, not a slice.")
			}
			if int(i) >= cur.Len() {
				log.Warnf("upstream.GetExtra(%s): index %d out of range", path, i)
				return nil, errors.New("Index out of range.")
			}
			cur = reflect.ValueOf(cur.Index(int(i)).Interface())
		}
	}
	return cur.Interface(), nil
}
Exemple #6
0
func OnDisconnect(handle DisconnectFunc, priority int) (err error) {
	if priority < 0 || priority > 39 {
		log.Errorf("Invalid priority %d: not in range [0, 39]", priority)
		return fmt.Errorf("priority check failure: %d not in range [0, 39]", priority)
	}
	if handle == nil {
		log.Error("Attempt to register nil handler")
		return errors.New("Nil handler!")
	}
	if disconnectHandlers[priority] == nil {
		disconnectHandlers[priority] = make(disconnectHandler, 0, 16)
	}
	disconnectHandlers[priority] = append(disconnectHandlers[priority], handle)
	log.Infof("Registered disconnect handler at priority %d", priority)
	return nil
}
Exemple #7
0
func OnPreStatusResponse(handle PreStatusResponseFunc, priority int) (err error) {
	if priority < 0 || priority > 39 {
		log.Errorf("Invalid priority %d: not in range [0, 39]", priority)
		return fmt.Errorf("priority check failure: %d not in range [0, 39]", priority)
	}
	if handle == nil {
		log.Error("Attempt to register nil handler")
		return errors.New("Nil handler!")
	}
	if preStatusResponseHandlers[priority] == nil {
		preStatusResponseHandlers[priority] = make(preStatusResponseHandler, 0, 16)
	}
	preStatusResponseHandlers[priority] = append(preStatusResponseHandlers[priority], handle)
	log.Infof("Registered preStatusResponse handler at priority %d", priority)
	return nil
}
Exemple #8
0
func OnStartProxy(handle StartProxyFunc, priority int) (err error) {
	if priority < 0 || priority > 39 {
		log.Errorf("Invalid priority %d: not in range [0, 39]", priority)
		return fmt.Errorf("priority check failure: %d not in range [0, 39]", priority)
	}
	if handle == nil {
		log.Error("Attempt to register nil handler")
		return errors.New("Nil handler!")
	}
	if startProxyHandlers[priority] == nil {
		startProxyHandlers[priority] = make(startProxyHandler, 0, 16)
	}
	startProxyHandlers[priority] = append(startProxyHandlers[priority], handle)
	log.Infof("Registered startProxy handler at priority %d", priority)
	return nil
}
Exemple #9
0
func OnLoginRequest(handle LoginRequestFunc, priority int) (err error) {
	if priority < 0 || priority > 39 {
		log.Errorf("Invalid priority %d: not in range [0, 39]", priority)
		return fmt.Errorf("priority check failure: %d not in range [0, 39]", priority)
	}
	if handle == nil {
		log.Error("Attempt to register nil handler")
		return errors.New("Nil handler!")
	}
	if loginRequestHandlers[priority] == nil {
		loginRequestHandlers[priority] = make(loginRequestHandler, 0, 16)
	}
	loginRequestHandlers[priority] = append(loginRequestHandlers[priority], handle)
	log.Infof("Registered pingRequest handler at priority %d", priority)
	return nil
}
Exemple #10
0
func userLogout(event *minegate.DisconnectEvent) {
	defer func() {
		if r := recover(); r != nil {
			log.Errorf("[conntrack] Recovered from panic. Programming error inside plugin. Please contact author ASAP!")
		}
	}()
	connID := event.GetConnID()
	ollock.Lock()
	defer ollock.Unlock()
	info, ok := conn_in[connID]
	if !ok {
		return
	}
	delete(conn_in, connID)
	online_list[info.Server].Remove(info.User)
	event.Infof("[conntrack] User %s logout from server %s.", info.User, info.Server)
	event.Infof("[conntrack] Upstream online user: %d. Total online user: %d", online_list[info.Server].Cardinality(), len(conn_in))
}
Exemple #11
0
func validateConfig() {
	invalid_upstreams := make([]int, 0, len(config.Upstream))
	for idx, upstream := range config.Upstream {
		if !upstream.Validate() {
			log.Errorf("Upstream %s is not activated.", upstream.Server)
			invalid_upstreams = append(invalid_upstreams, idx)
		}
	}
	for delta, idx := range invalid_upstreams {
		idx -= delta
		config.Upstream[idx] = nil
		config.Upstream = append(config.Upstream[:idx], config.Upstream[idx+1:]...)
	}
	if config.NotFound.Text == "" {
		log.Warn("Empty error text for not found error, use default string")
		config.NotFound.Text = "No such host."
	}
	config.chatNotFound = ToChatMsg(&config.NotFound)
}
Exemple #12
0
func confInit() {
	content, err := ioutil.ReadFile(config_file)
	if err != nil {
		log.Fatalf("unable to load config %s: %s", config_file, err.Error())
	}
	err = yaml.Unmarshal(content, &config)
	if err != nil {
		log.Fatalf("error when parsing config file %s: %s", config_file, err.Error())
	}
	validateConfig()
	if config.Log.Target != "" && config.Log.Target != "-" {
		config.Log.Target, _ = filepath.Abs(config.Log.Target)
		log.Info("log path: " + config.Log.Target)
	}
	log.Stop()
	if config.Daemonize {
		Daemonize()
	}
	log.Start()
	if config.Log.Level != "" {
		level := log.ToLevel(config.Log.Level)
		if level == log.INVALID {
			log.Errorf("Invalid log level %s", config.Log.Level)
		} else {
			log.SetLogLevel(level)
		}
	}
	if config.Log.Target != "" && config.Log.Target != "-" {
		err := log.Open(config.Log.Target)
		if err != nil {
			log.Fatalf("Unable to open log %s: %s", config.Log.Target, err.Error())
		}
	}
	log.Info("config loaded.")
	log.Info("server listen on: " + config.Listen_addr)
	log.Infof("%d upstream server(s) found", len(config.Upstream))
}
Exemple #13
0
func (event *NetworkEvent) Errorf(format string, v ...interface{}) {
	if event.log_prefix == "" {
		event.log_prefix = fmt.Sprintf("[#%d %s]", event.connID, event.RemoteAddr)
	}
	log.Errorf(event.log_prefix+format, v...)
}
Exemple #14
0
func (ws *WrapedSocket) Errorf(format string, v ...interface{}) {
	log.Errorf(ws.log_prefix+format, v...)
}
Exemple #15
0
func proxy(conn *WrapedSocket, upstream *Upstream, initial_pkt *mcproto.MCHandShake, ne *PostAcceptEvent) {
	addr, perr := net.ResolveTCPAddr("tcp", upstream.Server)
	var err error
	var upsock *net.TCPConn
	if perr == nil {
		upsock, err = net.DialTCP("tcp", nil, addr)
	}
	if err != nil || perr != nil {
		if err == nil {
			err = perr
		}
		log.Errorf("Unable to connect to upstream %s", upstream.Server)
		RejectHandler(conn, initial_pkt, upstream.ChatMsg)
		return
	}
	upconn := WrapUpstreamSocket(upsock, conn)
	if initial_pkt.NextState == 1 {
		// Handle ping here.
		conn.Debugf("ping proxy")
		pre := new(PingRequestEvent)
		pre.NetworkEvent = ne.NetworkEvent
		pre.Packet = initial_pkt
		pre.Upstream = upstream
		PingRequest(pre)
		if pre.Rejected() {
			if pre.reason == "" {
				conn.Warnf("Ping request was rejected.")
				pre.reason = "Request was rejected by plugin."
			} else {
				conn.Warnf("Ping request was rejected: %s", pre.reason)
			}
			e := mcchat.NewMsg(pre.reason)
			e.SetColor(mcchat.RED)
			e.SetBold(true)
			RejectHandler(conn, initial_pkt, e)
			return
		}
		init_raw, err := initial_pkt.ToRawPacket()
		if err != nil {
			log.Errorf("Unable to encode initial packet: %s", err.Error())
			conn.Close()
			upconn.Close()
			return
		}
		pkt, err := mcproto.ReadPacket(conn)
		if err != nil {
			conn.Errorf("Error when reading status request: %s", err.Error())
			conn.Close()
			upconn.Close()
			return
		}
		if !pkt.IsStatusRequest() {
			conn.Errorf("Invalid protocol: no status request.")
			conn.Close()
			upconn.Close()
			return
		}
		_, err = upconn.Write(init_raw.ToBytes())
		if err == nil {
			_, err = upconn.Write(pkt.ToBytes())
		}
		if err != nil {
			upconn.Errorf("write error: %s", err.Error())
			conn.Close()
			upconn.Close()
			return
		}
		resp_pkt, err := mcproto.ReadPacket(upconn)
		if err != nil {
			upconn.Errorf("invalid packet: %s", err.Error())
			conn.Close()
			upconn.Close()
			return
		}
		resp, err := resp_pkt.ToStatusResponse()
		if err != nil {
			upconn.Errorf("invalid packet: %s", err.Error())
			conn.Close()
			upconn.Close()
			return
		}
		psre := new(PreStatusResponseEvent)
		psre.NetworkEvent = ne.NetworkEvent
		psre.Packet = resp
		psre.Upstream = upstream
		PreStatusResponse(psre)
		resp_pkt, err = resp.ToRawPacket()
		if err != nil {
			conn.Errorf("invalid packet: %s", err.Error())
			conn.Close()
			upconn.Close()
			return
		}
		// We can handle ping request, close upstream
		upconn.Close()
		_, err = conn.Write(resp_pkt.ToBytes())
		if err != nil {
			conn.Errorf("write error: %s", err.Error())
			conn.Close()
			return
		}
		ping_pkt, err := mcproto.ReadPacket(conn)
		if err != nil || !ping_pkt.IsStatusPing() {
			if err == nil {
				err = errors.New("packet is not ping")
			}
			conn.Errorf("invalid packet: %s", err.Error())
			conn.Close()
			return
		}
		_, err = conn.Write(ping_pkt.ToBytes())
		conn.Close()
	} else {
		// Handle login here.
		conn.Debugf("login proxy")
		login_raw, err := mcproto.ReadPacket(conn)
		if err != nil {
			conn.Errorf("Read login packet: %s", err.Error())
			conn.Close()
			return
		}
		login_pkt, err := login_raw.ToLogin()
		if err != nil {
			conn.Errorf("invalid packet: %s", err.Error())
			conn.Close()
			return
		}
		lre := new(LoginRequestEvent)
		lre.NetworkEvent = ne.NetworkEvent
		lre.InitPacket = initial_pkt
		lre.LoginPacket = login_pkt
		lre.Upstream = upstream
		LoginRequest(lre)
		if lre.Rejected() {
			if lre.reason == "" {
				conn.Warnf("Ping request was rejected.")
				lre.reason = "Request was rejected by plugin."
			} else {
				conn.Warnf("Ping request was rejected: %s", lre.reason)
			}
			e := mcchat.NewMsg(lre.reason)
			e.SetColor(mcchat.RED)
			e.SetBold(true)
			RejectHandler(conn, initial_pkt, e)
			return
		}
		init_raw, err := initial_pkt.ToRawPacket()
		if err != nil {
			log.Errorf("Unable to encode initial packet: %s", err.Error())
			conn.Close()
			return
		}
		login_raw, err = login_pkt.ToRawPacket()
		if err != nil {
			log.Errorf("Unable to encode login packet: %s", err.Error())
			conn.Close()
			return
		}
		_, err = upconn.Write(init_raw.ToBytes())
		if err == nil {
			upconn.Write(login_raw.ToBytes())
		}
		if err != nil {
			upconn.Errorf("write error: %s", err.Error())
		}
		spe := new(StartProxyEvent)
		spe.Upstream = upstream
		spe.NetworkEvent = ne.NetworkEvent
		spe.InitPacket = initial_pkt
		spe.LoginPacket = login_pkt
		StartProxy(spe)
		go PipeIt(conn, upconn)
		go PipeIt(upconn, conn)
	}
}