Files
openfsd/processor_defs.go
2024-04-04 20:48:50 -07:00

625 lines
16 KiB
Go

package main
import (
"errors"
"github.com/renorris/openfsd/protocol"
"github.com/renorris/openfsd/vatsimauth"
"log"
"strings"
)
func PilotPositionProcessor(client *FSDClient, rawPacket string) *ProcessorResult {
// Parse & validate packet
pdu, err := protocol.ParsePilotPositionPDU(rawPacket)
if err != nil {
var fsdError *protocol.FSDError
result := NewProcessorResult()
if errors.As(err, &fsdError) {
result.AddReply(fsdError.Serialize())
}
result.Disconnect(true)
return result
}
// Check for valid source callsign
if pdu.From != client.Callsign {
result := NewProcessorResult()
result.AddReply(protocol.NewGenericFSDError(protocol.PDUSourceInvalidError).Serialize())
result.Disconnect(true)
return result
}
// Update location for post office
PO.SetLocation(client, pdu.Lat, pdu.Lng)
result := NewProcessorResult()
// Check if we should update SendFastEnabled
if client.SendFastEnabled && pdu.GroundSpeed == 0 {
client.SendFastEnabled = false
disableSendFastPDU := protocol.SendFastPDU{
From: protocol.ServerCallsign,
To: client.Callsign,
DoSendFast: false,
}
result.AddReply(disableSendFastPDU.Serialize())
} else if !client.SendFastEnabled && pdu.GroundSpeed > 0 {
client.SendFastEnabled = true
enableSendFastPDU := protocol.SendFastPDU{
From: protocol.ServerCallsign,
To: client.Callsign,
DoSendFast: true,
}
result.AddReply(enableSendFastPDU.Serialize())
}
// Broadcast position update
mail := NewMail(client)
mail.SetType(MailTypeBroadcastRanged)
mail.AddPacket(rawPacket)
result.AddMail(*mail)
return result
}
func ClientQueryProcessor(client *FSDClient, rawPacket string) *ProcessorResult {
// Parse & validate packet
pdu, err := protocol.ParseClientQueryPDU(rawPacket)
if err != nil {
var fsdError *protocol.FSDError
result := NewProcessorResult()
if errors.As(err, &fsdError) {
result.AddReply(fsdError.Serialize())
}
result.Disconnect(true)
return result
}
// Check for valid source callsign
if pdu.From != client.Callsign {
result := NewProcessorResult()
result.AddReply(protocol.NewGenericFSDError(protocol.PDUSourceInvalidError).Serialize())
result.Disconnect(true)
return result
}
switch pdu.To {
case protocol.ServerCallsign:
if pdu.QueryType == protocol.ClientQueryPublicIP {
ip := strings.Split(client.Conn.RemoteAddr().String(), ":")[0]
responsePDU := protocol.ClientQueryResponsePDU{
From: protocol.ServerCallsign,
To: client.Callsign,
QueryType: protocol.ClientQueryPublicIP,
Payload: ip,
}
result := NewProcessorResult()
result.AddReply(responsePDU.Serialize())
return result
}
return NewProcessorResult()
case protocol.ClientQueryBroadcastRecipient, protocol.ClientQueryBroadcastRecipientPilots:
mail := NewMail(client)
mail.SetType(MailTypeBroadcastRanged)
mail.AddRecipient(pdu.To)
mail.AddPacket(rawPacket)
result := NewProcessorResult()
result.AddMail(*mail)
return result
}
// Assume direct message client query
mail := NewMail(client)
mail.SetType(MailTypeDirect)
mail.AddRecipient(pdu.To)
mail.AddPacket(rawPacket)
result := NewProcessorResult()
result.AddMail(*mail)
return result
}
func ClientQueryResponseProcessor(client *FSDClient, rawPacket string) *ProcessorResult {
// Parse & validate packet
pdu, err := protocol.ParseClientQueryResponsePDU(rawPacket)
if err != nil {
var fsdError *protocol.FSDError
result := NewProcessorResult()
if errors.As(err, &fsdError) {
result.AddReply(fsdError.Serialize())
}
result.Disconnect(true)
return result
}
// Check for valid source callsign
if pdu.From != client.Callsign {
result := NewProcessorResult()
result.AddReply(protocol.NewGenericFSDError(protocol.PDUSourceInvalidError).Serialize())
result.Disconnect(true)
return result
}
if pdu.To == protocol.ServerCallsign {
return NewProcessorResult()
}
mail := NewMail(client)
mail.SetType(MailTypeDirect)
mail.AddRecipient(pdu.To)
mail.AddPacket(rawPacket)
result := NewProcessorResult()
result.AddMail(*mail)
return result
}
func PlaneInfoRequestProcessor(client *FSDClient, rawPacket string) *ProcessorResult {
// Parse & validate packet
pdu, err := protocol.ParsePlaneInfoRequestPDU(rawPacket)
if err != nil {
var fsdError *protocol.FSDError
result := NewProcessorResult()
if errors.As(err, &fsdError) {
result.AddReply(fsdError.Serialize())
}
result.Disconnect(true)
return result
}
// Check for valid source callsign
if pdu.From != client.Callsign {
result := NewProcessorResult()
result.AddReply(protocol.NewGenericFSDError(protocol.PDUSourceInvalidError).Serialize())
result.Disconnect(true)
return result
}
mail := NewMail(client)
mail.SetType(MailTypeDirect)
mail.AddRecipient(pdu.To)
mail.AddPacket(rawPacket)
result := NewProcessorResult()
result.AddMail(*mail)
return result
}
func PlaneInfoResponseProcessor(client *FSDClient, rawPacket string) *ProcessorResult {
// Parse & validate packet
pdu, err := protocol.ParsePlaneInfoResponsePDU(rawPacket)
if err != nil {
var fsdError *protocol.FSDError
result := NewProcessorResult()
if errors.As(err, &fsdError) {
result.AddReply(fsdError.Serialize())
}
result.Disconnect(true)
return result
}
// Check for valid source callsign
if pdu.From != client.Callsign {
result := NewProcessorResult()
result.AddReply(protocol.NewGenericFSDError(protocol.PDUSourceInvalidError).Serialize())
result.Disconnect(true)
return result
}
mail := NewMail(client)
mail.SetType(MailTypeDirect)
mail.AddRecipient(pdu.To)
mail.AddPacket(rawPacket)
result := NewProcessorResult()
result.AddMail(*mail)
return result
}
func FastPilotPositionProcessor(client *FSDClient, rawPacket string) *ProcessorResult {
// Parse & validate packet
pdu, err := protocol.ParseFastPilotPositionPDU(rawPacket)
if err != nil {
var fsdError *protocol.FSDError
result := NewProcessorResult()
if errors.As(err, &fsdError) {
result.AddReply(fsdError.Serialize())
}
result.Disconnect(true)
return result
}
// Check for valid source callsign
if pdu.From != client.Callsign {
result := NewProcessorResult()
result.AddReply(protocol.NewGenericFSDError(protocol.PDUSourceInvalidError).Serialize())
result.Disconnect(true)
return result
}
// Update location for post office if slow/stopped type
switch pdu.Type {
case protocol.FastPilotPositionTypeSlow, protocol.FastPilotPositionTypeStopped:
PO.SetLocation(client, pdu.Lat, pdu.Lng)
}
// Broadcast position update
mail := NewMail(client)
mail.SetType(MailTypeBroadcastRanged)
mail.AddPacket(rawPacket)
result := NewProcessorResult()
result.AddMail(*mail)
return result
}
func AuthChallengeProcessor(client *FSDClient, rawPacket string) *ProcessorResult {
// Parse & validate packet
pdu, err := protocol.ParseAuthChallengePDU(rawPacket)
if err != nil {
var fsdError *protocol.FSDError
result := NewProcessorResult()
if errors.As(err, &fsdError) {
result.AddReply(fsdError.Serialize())
}
result.Disconnect(true)
return result
}
// Check for valid source callsign
if pdu.From != client.Callsign {
result := NewProcessorResult()
result.AddReply(protocol.NewGenericFSDError(protocol.PDUSourceInvalidError).Serialize())
result.Disconnect(true)
return result
}
// Generate response for the client's challenge
challengeResponse := client.AuthSelf.GenerateResponse(pdu.Challenge)
client.AuthSelf.UpdateState(challengeResponse)
challengeResponsePDU := protocol.AuthChallengeResponsePDU{
From: protocol.ServerCallsign,
To: client.Callsign,
ChallengeResponse: challengeResponse,
}
// Send the client a new auth challenge
client.PendingAuthVerifyChallenge, err = vatsimauth.GenerateChallenge()
if err != nil {
log.Println("Error generating challenge string")
result := NewProcessorResult()
result.Disconnect(true)
return result
}
newChallengePDU := protocol.AuthChallengePDU{
From: protocol.ServerCallsign,
To: client.Callsign,
Challenge: client.PendingAuthVerifyChallenge,
}
result := NewProcessorResult()
result.AddReply(challengeResponsePDU.Serialize())
result.AddReply(newChallengePDU.Serialize())
return result
}
func AuthChallengeResponseProcessor(client *FSDClient, rawPacket string) *ProcessorResult {
// Parse & validate packet
pdu, err := protocol.ParseAuthChallengeResponsePDU(rawPacket)
if err != nil {
var fsdError *protocol.FSDError
result := NewProcessorResult()
if errors.As(err, &fsdError) {
result.AddReply(fsdError.Serialize())
}
result.Disconnect(true)
return result
}
// Check for valid source callsign
if pdu.From != client.Callsign {
result := NewProcessorResult()
result.AddReply(protocol.NewGenericFSDError(protocol.PDUSourceInvalidError).Serialize())
result.Disconnect(true)
return result
}
// Verify the response with the stored pending challenge
challengeResponse := client.AuthVerify.GenerateResponse(client.PendingAuthVerifyChallenge)
if challengeResponse != pdu.ChallengeResponse {
result := NewProcessorResult()
result.AddReply(protocol.NewGenericFSDError(protocol.UnauthorizedSoftwareError).Serialize())
result.Disconnect(true)
return result
}
client.AuthVerify.UpdateState(challengeResponse)
result := NewProcessorResult()
return result
}
func DeletePilotProcessor(client *FSDClient, rawPacket string) *ProcessorResult {
// Parse & validate packet
pdu, err := protocol.ParseDeletePilotPDU(rawPacket)
if err != nil {
var fsdError *protocol.FSDError
result := NewProcessorResult()
if errors.As(err, &fsdError) {
result.AddReply(fsdError.Serialize())
}
result.Disconnect(true)
return result
}
// Check for valid source callsign
if pdu.From != client.Callsign {
result := NewProcessorResult()
result.AddReply(protocol.NewGenericFSDError(protocol.PDUSourceInvalidError).Serialize())
result.Disconnect(true)
return result
}
// Check for valid CID
if pdu.CID != client.CID {
result := NewProcessorResult()
result.AddReply(protocol.NewGenericFSDError(protocol.SyntaxError).Serialize())
result.Disconnect(true)
return result
}
result := NewProcessorResult()
result.Disconnect(true)
return result
}
func PingProcessor(client *FSDClient, rawPacket string) *ProcessorResult {
// Parse & validate packet
pdu, err := protocol.ParsePingPDU(rawPacket)
if err != nil {
var fsdError *protocol.FSDError
result := NewProcessorResult()
if errors.As(err, &fsdError) {
result.AddReply(fsdError.Serialize())
}
result.Disconnect(true)
return result
}
// Check for valid source callsign
if pdu.From != client.Callsign {
result := NewProcessorResult()
result.AddReply(protocol.NewGenericFSDError(protocol.PDUSourceInvalidError).Serialize())
result.Disconnect(true)
return result
}
// Ignore if the ping isn't for the server
if pdu.To != protocol.ServerCallsign {
result := NewProcessorResult()
return result
}
result := NewProcessorResult()
pongPDU := protocol.PongPDU{
From: protocol.ServerCallsign,
To: client.Callsign,
Timestamp: pdu.Timestamp,
}
result.AddReply(pongPDU.Serialize())
return result
}
func BroadcastMessageProcessor(client *FSDClient, rawPacket string) *ProcessorResult {
// Parse & validate packet
pdu, err := protocol.ParseTextMessagePDU(rawPacket)
if err != nil {
var fsdError *protocol.FSDError
result := NewProcessorResult()
if errors.As(err, &fsdError) {
result.AddReply(fsdError.Serialize())
}
result.Disconnect(true)
return result
}
// Check for valid source callsign
if pdu.From != client.Callsign {
result := NewProcessorResult()
result.AddReply(protocol.NewGenericFSDError(protocol.PDUSourceInvalidError).Serialize())
result.Disconnect(true)
return result
}
// Ignore if the user doesn't have permission
if client.NetworkRating < protocol.NetworkRatingSUP {
return NewProcessorResult()
}
// Verify the To field is set to `*`
if pdu.To != "*" {
return NewProcessorResult()
}
mail := NewMail(client)
mail.SetType(MailTypeBroadcastAll)
mail.AddPacket(rawPacket)
result := NewProcessorResult()
result.AddMail(*mail)
return result
}
func WallopMessageProcessor(client *FSDClient, rawPacket string) *ProcessorResult {
// Parse & validate packet
pdu, err := protocol.ParseTextMessagePDU(rawPacket)
if err != nil {
var fsdError *protocol.FSDError
result := NewProcessorResult()
if errors.As(err, &fsdError) {
result.AddReply(fsdError.Serialize())
}
result.Disconnect(true)
return result
}
// Check for valid source callsign
if pdu.From != client.Callsign {
result := NewProcessorResult()
result.AddReply(protocol.NewGenericFSDError(protocol.PDUSourceInvalidError).Serialize())
result.Disconnect(true)
return result
}
// Verify the To field is set to `*S`
if pdu.To != "*S" {
return NewProcessorResult()
}
mail := NewMail(client)
mail.SetType(MailTypeBroadcastSupervisors)
mail.AddPacket(rawPacket)
result := NewProcessorResult()
result.AddMail(*mail)
return result
}
func RadioMessageProcessor(client *FSDClient, rawPacket string) *ProcessorResult {
// Parse & validate packet
pdu, err := protocol.ParseTextMessagePDU(rawPacket)
if err != nil {
var fsdError *protocol.FSDError
result := NewProcessorResult()
if errors.As(err, &fsdError) {
result.AddReply(fsdError.Serialize())
}
result.Disconnect(true)
return result
}
// Check for valid source callsign
if pdu.From != client.Callsign {
result := NewProcessorResult()
result.AddReply(protocol.NewGenericFSDError(protocol.PDUSourceInvalidError).Serialize())
result.Disconnect(true)
return result
}
// Verify the To field is a radio frequency
if !strings.HasPrefix(pdu.To, "@") || len(pdu.To) != 6 {
return NewProcessorResult()
}
mail := NewMail(client)
mail.SetType(MailTypeBroadcastRanged)
mail.AddPacket(rawPacket)
result := NewProcessorResult()
result.AddMail(*mail)
return result
}
func DirectMessageProcessor(client *FSDClient, rawPacket string) *ProcessorResult {
// Parse & validate packet
pdu, err := protocol.ParseTextMessagePDU(rawPacket)
if err != nil {
var fsdError *protocol.FSDError
result := NewProcessorResult()
if errors.As(err, &fsdError) {
result.AddReply(fsdError.Serialize())
}
result.Disconnect(true)
return result
}
// Check for valid source callsign
if pdu.From != client.Callsign {
result := NewProcessorResult()
result.AddReply(protocol.NewGenericFSDError(protocol.PDUSourceInvalidError).Serialize())
result.Disconnect(true)
return result
}
mail := NewMail(client)
mail.SetType(MailTypeDirect)
mail.AddRecipient(pdu.To)
mail.AddPacket(rawPacket)
result := NewProcessorResult()
result.AddMail(*mail)
return result
}
func KillRequestProcessor(client *FSDClient, rawPacket string) *ProcessorResult {
// Parse & validate packet
pdu, err := protocol.ParseKillRequestPDU(rawPacket)
if err != nil {
var fsdError *protocol.FSDError
result := NewProcessorResult()
if errors.As(err, &fsdError) {
result.AddReply(fsdError.Serialize())
}
result.Disconnect(true)
return result
}
// Check for valid source callsign
if pdu.From != client.Callsign {
result := NewProcessorResult()
result.AddReply(protocol.NewGenericFSDError(protocol.PDUSourceInvalidError).Serialize())
result.Disconnect(true)
return result
}
// Check if client has permission
if client.NetworkRating < protocol.NetworkRatingSUP {
return NewProcessorResult()
}
victim, err := PO.GetClient(pdu.To)
if err != nil {
result := NewProcessorResult()
if errors.Is(err, CallsignNotRegisteredError) {
result.AddReply(protocol.NewGenericFSDError(protocol.NoSuchCallsignError).Serialize())
}
return result
}
result := NewProcessorResult()
replyPDU := protocol.TextMessagePDU{
From: protocol.ServerCallsign,
To: client.Callsign,
Message: "",
}
// Attempt a non-blocking kill
select {
case victim.Kill <- rawPacket:
replyPDU.Message = "Killed " + pdu.To
default:
replyPDU.Message = "ERROR: unable to kill " + pdu.To
}
result.AddReply(replyPDU.Serialize())
return result
}