Пример #1
0
func (u *User) Kick(reason string) {
	u.Leave()
	u.Kicked = true
	buf := make([]byte, len(reason)+2)
	b := buf
	buf, _ = proto.WriteString(buf, reason)
	pkt := proto.NewPacket(5, b)
	pkt.Sign(u.Privkey)
	u.Conn.Write(pkt.Bytes())
	u.Conn.Close()

}
Пример #2
0
func (u *User) SendMessage(from string, msg string) {
	buf := make([]byte, len(from)+len(msg)+4)
	b := buf
	buf, err := proto.WriteString(buf, from)
	buf, err = proto.WriteString(buf, msg)
	pkt := proto.NewPacket(13, b)
	pkt.Sign(u.Privkey)
	_, err = u.Conn.Write(pkt.Bytes())
	if err != nil {
		u.Kicked = true
		u.Conn.Close()
		return
	}
}
Пример #3
0
func (u *User) refreshBoard() {
	if u.Game == nil {
		return
	}
	var placed, color uint64
	for i := 0; i < 8; i++ {
		for j := 0; j < 8; j++ {
			this := uint((i << 3) | j)
			if u.Game.Board[i][j] != 0 {
				placed |= uint64(1) << this
				if u.Game.Board[i][j] == 2 {
					color |= uint64(1) << this
				}
			}
		}
	}
	black := "[Empty]"
	white := "[Empty]"
	if u.Game.Black != nil {
		black = u.Game.Black.Name
	}
	if u.Game.White != nil {
		white = u.Game.White.Name
	}
	buf := make([]byte, 16384)
	binary.BigEndian.PutUint64(buf, placed)
	binary.BigEndian.PutUint64(buf[8:], color)
	buf[16] = byte(u.Game.Turn)
	b := buf[17:]
	b, _ = proto.WriteString(b, white)
	b, _ = proto.WriteString(b, black)
	length := 16384 - len(b)
	pkt := proto.NewPacket(12, buf[:length])
	pkt.Sign(u.Privkey)
	_, err := u.Conn.Write(pkt.Bytes())
	if err != nil {
		u.Kicked = true
		u.Conn.Close()
		return
	}
}
Пример #4
0
func upstream() {
	buff := make([]byte, 16384)
	for {
		line, err := rl.Readline()
		if err == readline.ErrInterrupt {
			line = "exit"
		}
		if err == io.EOF {
			continue
		}
		line = strings.TrimSpace(line)
		switch {
		case strings.HasPrefix(line, "login "):
			// arg1 => username
			args, err := sw.Parse(line)
			if err != nil {
				fmt.Fprintln(stderr, "Invalid line:", err.Error())
				continue
			}
			args = args[1:]
			if len(args) == 0 {
				fmt.Fprintf(stderr, "Usage: login username\n")
				continue
			}
			if len(args) == 1 {
				proto.WriteString(buff, args[0])
				pkt := proto.NewPacket(4, buff[:len(args[0])+2])
				pkt.Sign(privkey)
				_, err = user.Conn.Write(pkt.Bytes())
				if err != nil {
					fmt.Fprintf(stderr, "Write packet error: %s\n", err.Error())
					panic("Socket error!")
				}
			}
		case strings.HasPrefix(line, "exit"):
			// arg1 => reason
			reason := "Disconnected"
			args, err := sw.Parse(line)
			if err != nil {
				fmt.Fprintln(stderr, "Invalid line:", err.Error())
				continue
			}
			if len(args) >= 2 {
				reason = args[1]
			}
			proto.WriteString(buff, reason)
			pkt := proto.NewPacket(5, buff[:len(reason)+2])
			pkt.Sign(privkey)
			_, err = user.Conn.Write(pkt.Bytes())
			if err != nil {
				fmt.Fprintf(stderr, "Write packet error: %s\n", err.Error())
				panic("Socket error!")
			}
			time.Sleep(500 * time.Millisecond)
			os.Exit(0)
		case line == "games":
			pkt := proto.NewPacket(6, []byte{})
			pkt.Sign(privkey)
			_, err = user.Conn.Write(pkt.Bytes())
			if err != nil {
				fmt.Fprintf(stderr, "Write packet error: %s\n", err.Error())
				panic("Socket error!")
			}
		case line == "players":
			pkt := proto.NewPacket(7, []byte{})
			pkt.Sign(privkey)
			_, err = user.Conn.Write(pkt.Bytes())
			if err != nil {
				fmt.Fprintf(stderr, "Write packet error: %s\n", err.Error())
				panic("Socket error!")
			}
		case strings.HasPrefix(line, "join "):
			// arg1 => roomid

			args, err := sw.Parse(line)
			if err != nil {
				fmt.Fprintln(stderr, "Invalid line:", err.Error())
				continue
			}
			args = args[1:]
			if len(args) == 0 {
				fmt.Fprintf(stderr, "Usage: join roomid\n")
				continue
			}
			if len(args) == 1 {
				r, err := strconv.Atoi(args[0])
				if err != nil {
					fmt.Fprintf(stderr, "Invalid roomid %s\n", args[0])
				}
				roomid := uint16(r)
				binary.BigEndian.PutUint16(buff, roomid)
				pkt := proto.NewPacket(8, buff[:2])
				pkt.Sign(privkey)
				_, err = user.Conn.Write(pkt.Bytes())
				if err != nil {
					fmt.Fprintf(stderr, "Write packet error: %s\n", err.Error())
					panic("Socket error!")
				}
			}
		case line == "leave":
			pkt := proto.NewPacket(9, []byte{})
			pkt.Sign(privkey)
			_, err = user.Conn.Write(pkt.Bytes())
			if err != nil {
				fmt.Fprintf(stderr, "Write packet error: %s\n", err.Error())
				panic("Socket error!")
				return
			}
		case line == "restart":
			pkt := proto.NewPacket(10, []byte{})
			pkt.Sign(privkey)
			_, err = user.Conn.Write(pkt.Bytes())
			if err != nil {
				fmt.Fprintf(stderr, "Write packet error: %s\n", err.Error())
				panic("Socket error!")
			}
		case strings.HasPrefix(line, "place "):
			args, err := sw.Parse(line)
			if err != nil {
				fmt.Fprintln(stderr, "Invalid line:", err.Error())
				continue
			}
			args = args[1:]
			if len(args) < 2 {
				fmt.Fprintf(stderr, "Usage: place x y\n")
				continue
			}
			// arg1 => x, arg2 => y
			x, err := strconv.Atoi(args[0])
			if err != nil {
				fmt.Fprintf(stderr, "Invalid number %s\n", args[0])
			}
			y, err := strconv.Atoi(args[1])
			if err != nil {
				fmt.Fprintf(stderr, "Invalid number %s\n", args[1])
			}
			buff[0] = byte((x << 4) | y)
			pkt := proto.NewPacket(11, buff[:1])
			pkt.Sign(privkey)
			_, err = user.Conn.Write(pkt.Bytes())
			if err != nil {
				fmt.Fprintf(stderr, "Write packet error: %s\n", err.Error())
				panic("Socket error!")
			}
		case strings.HasPrefix(line, "msg "):
			args, err := sw.Parse(line)
			if err != nil {
				fmt.Fprintln(stderr, "Invalid line:", err.Error())
				continue
			}
			args = args[1:]
			if len(args) < 2 {
				fmt.Fprintf(stderr, "Usage: msg player message\n")
				continue
			}
			b := buff
			b, _ = proto.WriteString(b, args[0])
			b, _ = proto.WriteString(b, args[1])
			pkt := proto.NewPacket(13, buff[:len(args[0])+len(args[1])+4])
			pkt.Sign(privkey)
			_, err = user.Conn.Write(pkt.Bytes())
			if err != nil {
				fmt.Fprintf(stderr, "Write packet error: %s\n", err.Error())
				panic("Socket error!")
			}
		default:
			fmt.Fprintln(stderr, "Commands: ")
			fmt.Fprint(stderr, completer.Tree("    "))
		}
	}
}
Пример #5
0
func handshake(conn net.Conn) bool {
	var err error
	user.Conn = conn
	user.Pubkey = pubkey
	user.Privkey = privkey
	buf := make([]byte, 64)
	challenge := make([]byte, 32)
	rand.Read(challenge)
	copy(buf, (*user.Pubkey)[:])
	copy(buf[32:], challenge)
	pkt := proto.NewPacket(0, buf)
	pkt.Sign(privkey)
	_, err = user.Conn.Write(pkt.Bytes())
	if err != nil {
		fmt.Fprintf(stderr, "Write packet error: %s\n", err.Error())
		user.Conn.Close()
		return false
	}
	pkt, err = proto.ReadPacket(user.Conn)
	if err != nil {
		fmt.Fprintf(stderr, "Read packet error: %s\n", err.Error())
		user.Conn.Close()
		return false
	}
	if pkt.Frametype != 1 || len(pkt.Payload) != 96 {
		fmt.Fprintf(stderr, "Unexpected packet type %d\n", pkt.Frametype)
		user.Conn.Close()
		return false
	}
	user.RPubKey = new([ed25519.PublicKeySize]byte)
	copy((*user.RPubKey)[:], pkt.Payload[:32])
	if !pkt.Validate(user.RPubKey) {
		fmt.Fprintf(stderr, "Invalid sign for packet!\n")
		user.Conn.Close()
		return false
	}
	if !bytes.Equal(challenge, pkt.Payload[32:64]) {
		fmt.Fprintf(stderr, "Invalid challenge data!\n")
		user.Conn.Close()
		return false
	}
	pkt = proto.NewPacket(2, pkt.Payload[64:])
	pkt.Sign(privkey)
	_, err = user.Conn.Write(pkt.Bytes())
	if err != nil {
		fmt.Fprintf(stderr, "Write packet error: %s\n", err.Error())
		user.Conn.Close()
		return false
	}
	pkt, err = proto.ReadPacket(user.Conn)
	if err != nil {
		fmt.Fprintf(stderr, "Read packet error: %s\n", err.Error())
		user.Conn.Close()
		return false
	}
	if pkt.Frametype != 3 {
		fmt.Fprintf(stderr, "Unexpected packet type %d\n", pkt.Frametype)
		user.Conn.Close()
		return false
	}
	if !pkt.Validate(user.RPubKey) {
		fmt.Fprintf(stderr, "Invalid sign for packet!\n")
		user.Conn.Close()
		return false
	}
	return true
}
Пример #6
0
func client(conn net.Conn, id int) {
	user := new(common.User)
	user.Conn = conn
	user.Pubkey = pubkey
	user.Privkey = privkey
	pkt, err := proto.ReadPacket(user.Conn)
	if err != nil {
		fmt.Fprintf(rl.Stderr(), "[Conn %d] Read packet error: %s\n", id, err.Error())
		user.Conn.Close()
		return
	}
	if pkt.Frametype != 0 || len(pkt.Payload) != 64 {
		fmt.Fprintf(rl.Stderr(), "[Conn %d] Unexpected packet type %d\n", id, pkt.Frametype)
		user.Conn.Close()
		return
	}
	user.RPubKey = new([ed25519.PublicKeySize]byte)
	copy(user.RPubKey[:], pkt.Payload[:32])
	if !pkt.Validate(user.RPubKey) {
		fmt.Fprintf(rl.Stderr(), "[Conn %d] Invalid sign for packet!\n", id)
		user.Conn.Close()
		return
	}
	// Client key & challenge
	payload := make([]byte, 96)
	copy(payload, pubkey[:])
	copy(payload[32:], pkt.Payload[32:])
	challenge := make([]byte, 32)
	_, err = rand.Read(challenge)
	if err != nil {
		fmt.Fprintf(rl.Stderr(), "[Conn %d] !!WARNING!!, random pool error: %s, using empty challenge string!\n", id, err.Error())
	}
	copy(payload[64:], challenge)
	pkt = proto.NewPacket(1, payload)
	pkt.Sign(privkey)
	_, err = user.Conn.Write(pkt.Bytes())
	if err != nil {
		fmt.Fprintf(rl.Stderr(), "[Conn %d] Write packet error: %s\n", id, err.Error())
		user.Conn.Close()
		return
	}
	// Server validation
	pkt, err = proto.ReadPacket(user.Conn)
	if err != nil {
		fmt.Fprintf(rl.Stderr(), "[Conn %d] Read packet error: %s\n", id, err.Error())
		user.Conn.Close()
		return
	}
	if !pkt.Validate(user.RPubKey) {
		fmt.Fprintf(rl.Stderr(), "[Conn %d] Invalid sign for packet!\n", id)
		user.Conn.Close()
		return
	}
	if pkt.Frametype != 2 || len(pkt.Payload) != 32 {
		fmt.Fprintf(rl.Stderr(), "[Conn %d] Unexpected packet type %d\n", id, pkt.Frametype)
		user.Conn.Close()
		return
	}
	if !bytes.Equal(pkt.Payload, challenge) {
		fmt.Fprintf(rl.Stderr(), "[Conn %d] Invalid challenge data!\n", id)
		user.Conn.Close()
		return
	}
	pkt = proto.NewPacket(3, []byte{})
	pkt.Sign(privkey)
	_, err = user.Conn.Write(pkt.Bytes())
	if err != nil {
		fmt.Fprintf(rl.Stderr(), "[Conn %d] Write packet error: %s\n", id, err.Error())
		user.Conn.Close()
		return
	}
	// Login
	for {
		pkt, err = proto.ReadPacket(user.Conn)
		if err != nil {
			fmt.Fprintf(rl.Stderr(), "[Conn %d] Read packet error: %s\n", id, err.Error())
			user.Conn.Close()
			return
		}
		if !pkt.Validate(user.RPubKey) {
			fmt.Fprintf(rl.Stderr(), "[Conn %d] Invalid sign for packet!\n", id)
			user.Conn.Close()
			return
		}
		if pkt.Frametype != 4 {
			fmt.Fprintf(rl.Stderr(), "[Conn %d] Unexpected packet type %d\n", id, pkt.Frametype)
			user.Conn.Close()
			return
		}
		username, _, err := proto.ReadString(pkt.Payload)
		if err != nil {
			fmt.Fprintf(rl.Stderr(), "[Conn %d] Unexpected packet type %d\n", id, pkt.Frametype)
			user.Conn.Close()
			return
		}
		if _, ok := users[username]; !ok {
			// Username ok
			fmt.Fprintf(rl.Stderr(), "[Conn %d] User %s logged in, from %s\n", id, username, user.Conn.RemoteAddr().String())
			pkt = proto.NewPacket(4, []byte{0})
			pkt.Sign(privkey)
			_, err = user.Conn.Write(pkt.Bytes())
			if err != nil {
				fmt.Fprintf(rl.Stderr(), "[Conn %d] Write packet error: %s\n", id, err.Error())
				user.Conn.Close()
				return
			}
			users[username] = user
			user.Name = username
			defer func(name string) { users[name].Kick(""); delete(users, name) }(username) // Delete on leave
			break
		}
		pkt = proto.NewPacket(4, []byte{1})
		pkt.Sign(privkey)
		_, err = user.Conn.Write(pkt.Bytes())
		if err != nil {
			fmt.Fprintf(rl.Stderr(), "[Conn %d] Write packet error: %s\n", id, err.Error())
			user.Conn.Close()
			return
		}
	}
	for !user.Kicked {
		pkt, err := proto.ReadPacket(user.Conn)
		if err != nil {
			fmt.Fprintf(rl.Stderr(), "[Conn %d] Read packet error: %s\n", id, err.Error())
			user.Conn.Close()
			return
		}
		if !pkt.Validate(user.RPubKey) {
			fmt.Fprintf(rl.Stderr(), "[Conn %d] Invalid sign for packet!\n", id)
			user.Conn.Close()
			return
		}
		buf := make([]byte, 16384)
		switch pkt.Frametype {
		case 5: // Quit packet
			reason, _, err := proto.ReadString(pkt.Payload)
			if err != nil {
				fmt.Fprintf(rl.Stderr(), "[Conn %d] Unexpected packet type %d\n", id, pkt.Frametype)
				user.Conn.Close()
				return
			}
			fmt.Fprintf(rl.Stderr(), "[Conn %d] Client Quit: %s\n", id, reason)
			user.Conn.Close()
			return
		case 6: // Roomlist request
			b := buf
			for rid, room := range games {
				if room == nil {
					continue
				}
				usera := ""
				if room.Black != nil {
					usera = room.Black.Name
				}
				userb := ""
				if room.White != nil {
					userb = room.White.Name
				}
				binary.BigEndian.PutUint16(b, rid)
				b = b[2:]
				b, _ = proto.WriteString(b, usera)
				b, _ = proto.WriteString(b, userb)
			}
			length := 16384 - len(b)
			b = buf[:length]
			pkt = proto.NewPacket(6, b)
			pkt.Sign(privkey)
			_, err = user.Conn.Write(pkt.Bytes())
			if err != nil {
				fmt.Fprintf(rl.Stderr(), "[Conn %d] Write packet error: %s\n", id, err.Error())
				user.Conn.Close()
				return
			}
		case 7: // Player list request
			b := buf
			for username := range users {
				b, _ = proto.WriteString(b, username)
			}
			length := 16384 - len(b)
			b = buf[:length]
			pkt = proto.NewPacket(7, b)
			pkt.Sign(privkey)
			_, err = user.Conn.Write(pkt.Bytes())
			if err != nil {
				fmt.Fprintf(rl.Stderr(), "[Conn %d] Write packet error: %s\n", id, err.Error())
				user.Conn.Close()
				return
			}
		case 8:
			if len(pkt.Payload) != 2 {
				fmt.Fprintf(rl.Stderr(), "[Conn %d] Unexpected packet type %d\n", id, pkt.Frametype)
				user.Conn.Close()
				return
			}
			jrid := binary.BigEndian.Uint16(pkt.Payload)
			room := games[jrid]
			result := user.Join(room)
			pkt = proto.NewPacket(8, []byte{result})
			pkt.Sign(privkey)
			_, err = user.Conn.Write(pkt.Bytes())
			if err != nil {
				fmt.Fprintf(rl.Stderr(), "[Conn %d] Write packet error: %s\n", id, err.Error())
				user.Conn.Close()
				return
			}
		case 9:
			user.Leave()
			pkt = proto.NewPacket(9, []byte{})
			pkt.Sign(privkey)
			_, err = user.Conn.Write(pkt.Bytes())
			if err != nil {
				fmt.Fprintf(rl.Stderr(), "[Conn %d] Write packet error: %s\n", id, err.Error())
				user.Conn.Close()
				return
			}
		case 10:
			user.Restart()
			if user.Game.Black != nil {
				user.Game.Black.SendMessage("", fmt.Sprintf("%s is now ready.", user.Name))
			}
			if user.Game.White != nil {
				user.Game.White.SendMessage("", fmt.Sprintf("%s is now ready.", user.Name))
			}
		case 11:
			if len(pkt.Payload) != 1 {
				fmt.Fprintf(rl.Stderr(), "[Conn %d] Unexpected packet type %d\n", id, pkt.Frametype)
				user.Conn.Close()
				return
			}
			xy := uint8(pkt.Payload[0])
			x := xy >> 4
			y := xy & 15
			if user.Game.Black == user {
				if !user.Game.Place(x, y, 1) {
					user.SendMessage("", "Invalid operation")
				}
			} else {
				if !user.Game.Place(x, y, 2) {
					user.SendMessage("", "Invalid operation")
				}
			}
		case 13:
			p := pkt.Payload
			dest, p, err := proto.ReadString(p)
			if err != nil {
				fmt.Fprintf(rl.Stderr(), "[Conn %d] Unexpected packet type %d\n", id, pkt.Frametype)
				user.Conn.Close()
				return
			}
			msg, p, err := proto.ReadString(p)
			if err != nil {
				fmt.Fprintf(rl.Stderr(), "[Conn %d] Unexpected packet type %d\n", id, pkt.Frametype)
				user.Conn.Close()
				return
			}
			if dest != "" {
				u, ok := users[dest]
				if !ok {
					user.SendMessage("", "No such user.")
				} else {
					go u.SendMessage(user.Name, msg)
				}
			}
		}
	}
}