package ftp import ( "strings" osm "git.loafle.net/overflow/service_matcher-go" ) // FTP Status codes, defined in RFC 959 const ( statusReadyServer = "120" statusOK = "200" statusNewConnectOK = "220" statusSystemNameOK = "215" statusCloseConnect = "221" statusUnkownCMD = "202" statusTlsUseOK = "234" statusCloseControlConnect = "421" statusSyntaxErr = "500" statusParamSyntaxErr = "501" statusNotUseCMD = "502" statusIncorrectCMD = "503" statusNotLoggedIn = "530" statusTlsNotUse = "534" statusNeedUserId = "332" ) type FTPMatcher struct { osm.Matchers } func (m *FTPMatcher) Key(matchCtx *osm.MatchCtx) string { return "FTP" } func (m *FTPMatcher) Type(matchCtx *osm.MatchCtx) string { return "NETWORK" } func (m *FTPMatcher) Vendor(matchCtx *osm.MatchCtx) string { v := "UNKNOWN" if _v, ok := matchCtx.GetAttribute("comment"); ok { if strings.Contains(_v, "Pure-FTPd") { v = "Pure-FTPd" } } return v } func (m *FTPMatcher) Version(matchCtx *osm.MatchCtx) string { return "UNKNOWN" } func (m *FTPMatcher) OsType(matchCtx *osm.MatchCtx) string { return "UNKNOWN" } func (m *FTPMatcher) OsVersion(matchCtx *osm.MatchCtx) string { return "UNKNOWN" } func (m *FTPMatcher) Name(matchCtx *osm.MatchCtx) string { name := "FTP" if v, ok := matchCtx.GetAttribute("comment"); ok { if strings.Contains(v, "Pure-FTPd") { name = "Pure-FTPd" } } return name } func (m *FTPMatcher) IsPrePacket() bool { return true } func (m *FTPMatcher) HasResponse(matchCtx *osm.MatchCtx, index int) bool { return true } func (m *FTPMatcher) IsError(matchCtx *osm.MatchCtx, index int, packet *osm.Packet) bool { return false } func (m *FTPMatcher) Match(matchCtx *osm.MatchCtx, index int, packet *osm.Packet) error { if packet == nil || !packet.Valid() { return osm.NoPacketReceivedError() } str := strings.Split(string(packet.Bytes()), "\r\n")[0] if len(str) < 4 { return osm.NotMatchedError() } code := str[:3] if index == 0 { switch code { case statusNewConnectOK, statusReadyServer: matchCtx.SetAttribute("comment", str[4:]) return nil } } else if index == 1 { switch code { case statusCloseConnect, statusSyntaxErr: return nil } } return osm.NotMatchedError() } func NewMatcher() osm.Matcher { m := &FTPMatcher{} quitStr := "QUIT\r\n" quitByte := make([]byte, len(quitStr)) copy(quitByte[:], quitStr) m.AddPacket(osm.NewPacket(quitByte, len(quitStr))) return m }