Verbindung zum IRC Server, No Ident Response

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
JonnyDamnnox
User
Beiträge: 68
Registriert: Sonntag 10. März 2013, 21:14

Hallo,
Ich will einen kleinen simplen IRC Bot programmieren und dann mit dem http://nltk.org/ was draus machen.
Also ich habe einen kleinen client geschrieben(mit Hilfe von BlacKJack verbessert :D thx)

Code: Alles auswählen

import socket
from contextlib import closing

def main():
	with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock:
		print "Socket(Client)"
		host = raw_input("Host(z.B. google.de):\n>")
		port = int(raw_input("Welcher Port?:\n>"))
		input = raw_input("Was soll gesendet werden?:\n>")
		sock.connect((host, port))
		sock.sendall(input+ "\n")
		print "Verbindung aufgebaut zu {0}(IP:{1}), gesendet: {2}".format(
	        host, socket.gethostbyname(host), input
		)
		while True:
			antwort = sock.recv(4096)
			print antwort
			
		
if __name__ == "__main__":
	main()


Wenn ich nun die IRC Daten eingebe,
z.B. host: irc.freenode.net port: 6667 nachricht: PASS blabla NICK blabla USER bla bla irc.freenode.net 235.25345.33
(eigene ip, ist jetzt nur ein beispiel) :JonnyNonny (also das muss man ja alles eingeben weil irc protokoll), und dann
auf den server connected dann kommt als letztes eben dieses "No ident response".

In der offiziellen IRC Protokoll doc steht leider nicht viel,
nur das es einen ident-server gibt, und das man den eben manchmal braucht.
Jetzt hab ich mich informiert und rausbekommen das der IRC Server mir bei diesem
Prozess eine ID auf dem Port 113 zurückschickt, und ich diese ID dann
rückwärts(mit noch ein paar anderen Sachen) wieder an ihn schicken muss.
Wenn das nicht passiert gibt es eben dieses "no ident respone".

Jetzt frag ich mich wie ich die Nachricht auf dem Port auffangen kann.
Ich hab einen kleinen server dazu programmiert der auf Port 113 ein listening macht.
Also das client Programm gestartet, dann zum IRC-Server connected und währendessen hat dann
der server "gelisteninged", leider kommt nix durch :roll:
Ich hab es auch noch mal mit telnet versucht, da geht auch nix durch.
Bei meinem Router hab ich auch den Port 113 "weitergeleitet" und es sollte nun offen sein.

Könnte ich den client nicht so schreiben das es gleichzeit auch "hört" was der server schickt
und dies eben wie gewollt wieder zurück schickt??(also wenn es klappt)


Das ist der code von dem server mit dem ich es mit telnet versucht habe(ist aus einem Tutorial,
einfach um zu sehen ob es überhaupt klappt(was es ja nicht hat). Ich hatte auch etwas eigenes mit
connect/listen usw. in meinen eigenen client ganz oben eingebaut, hat leider noch nicht geklappt)

Code: Alles auswählen

import socket
import sys
 
HOST = ''   # Symbolic name meaning all available interfaces
PORT = 8888 # Arbitrary non-privileged port
 
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print 'Socket created'
 
try:
    s.bind((HOST, PORT))
except socket.error , msg:
    print 'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
    sys.exit()
     
print 'Socket bind complete'
 
s.listen(10)
print 'Socket now listening'
 
#now keep talking with the client
while 1:
    #wait to accept a connection - blocking call
    conn, addr = s.accept()
    print 'Connected with ' + addr[0] + ':' + str(addr[1])
     
    data = conn.recv(1024)
    reply = 'OK...' + data
    if not data:
        break
     
    conn.sendall(reply)
print conn.recv(1024)
conn.close()
s.close()


Gruß
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo.

Du solltest es erstmal mit Telnet zum laufen bekommen, alles andere ist nicht besonders sinnvoll. Es nützt ja nichts Fehler in deinem Code zu suchen, wenn du das IRC-Protokoll noch nicht richtig verstanden hast. Was sagt denn Wireshark, kommt bei dir überhaupt irgend eine Antwort an?
JonnyDamnnox hat geschrieben:"gelisteninged"
Wuhaa, ich habe noch nie so viele grammatische Fehler in nur einem Wort gesehen. Und das dann auch noch zweisprachig. Respekt ;-)
Das Leben ist wie ein Tennisball.
JonnyDamnnox
User
Beiträge: 68
Registriert: Sonntag 10. März 2013, 21:14

Hi EyDu :)
Ja also ich empfange jetzt doch etwas per telnet. Das heißt es muss auch anders rum gehen.
Also hier ein Bild von wireshark:
Leider sehr unübersichtlich, ich weiß das das was übertragen wird dann noch mal wenn man drauf klickt unten angezeigt wird(Zeichenketten usw). Aber was ist denn da das richtige??

http://s1.directupload.net/file/d/3208/sm96c9ns_jpg.htm

??
Und dann muss ich es ja wieder zurück senden, aber ich denk das krieg ich auch alleine hin, wenns dann mal klappt.
Danke für die Antwort.
Und sry wegen dem komischen Wort, ich lese so viel in englisch in letzter Zeit das ich gar nicht mehr weiß wie ich mich in deutsch ausdrücken soll :D

Gruß
JonnyDamnnox
User
Beiträge: 68
Registriert: Sonntag 10. März 2013, 21:14

Alles klar, ich bekomm jetzt die Nummer. Hab es noch mal mit einem eigens geschriebenen Server versucht und powershell spuckt zwei Nummern aus, das wirds wohl sein.
Ich werd weiter dran rumfriemeln.

Gruß
JonnyDamnnox
User
Beiträge: 68
Registriert: Sonntag 10. März 2013, 21:14

Hallo :D
Also ich glaub es jetzt verstanden zu haben. Es gibt IRC Server bei denen braucht man neben dem client, der connected noch einen ident-server. D.h. ich muss einfach einen neue server machen der den port 113 abhorcht und dann antwortet. Ich hab das jetzt mal so versucht:

Code: Alles auswählen

#client der mit irc-server kontakt aufnimmt
import socket
from contextlib import closing

def main():
	with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock:
		print "Socket(Client)"
		host = raw_input("Host(z.B. google.de):\n>")#irc.freenode.net
		port = int(raw_input("Welcher Port?:\n>"))#6667
		input = raw_input("Was soll gesendet werden?:\n>")#einfach zum test: PASS testpass
		sock.connect((host, port))
		sock.sendall(input+ "\n")
		print "Verbindung aufgebaut zu {0}(IP:{1}), gesendet: {2}".format(
	        host, socket.gethostbyname(host), input
		)
		while True:
			antwort = sock.recv(4096)
			print antwort #No ident respond wenn man nix zurückschickt
			
		
if __name__ == "__main__":
	main()

Code: Alles auswählen

#Ident-server
#Lauscht Port 113 ab fuer ID
#ID hat die form xxxxx,6667:USERID:UNIX:Nickname
#xxxxx,6667 bekomme ich über 113 geschickt

import socket

def main():
	sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	print "Simple client(server) application for localhost"
	port = int(raw_input("Port der gelaucht werden soll?:\n>"))#113
	host = ""
	sock.bind(("", port))
	sock.listen(5)
	conn, addr = sock.accept()
	print "Verbunden mit {0}".format(addr)
	data = conn.recv(1024)
	sock.sendall(data+":USERID:UNIX:fernsehduff")
	print data
	
if __name__ == "__main__":
	main()

Also ich lasse erst den ident-server laufen damit er port 113 abhört, dann starte ich den client und geb alles ein damit er mir dann die ID schickt. Dann sollte der server die empfangene ID wieder zurück an irc server schicken. Leider bekomme ich diese Fehlermeldung:

File "C:\Python27\lib\socket.py", line 224, in meth
return getattr(self._sock,name)(*args)
socket.error: [Errno 10057] Eine Anforderung zum Senden oder Empfangen von Daten
wurde verhindert, da der Socket nicht verbunden ist und (beim Senden ³ber einen
Datagrammsocket mit einem sendto-Aufruf) keine Adresse angegeben wurde.

In der Fehlermeldung steht aber noch etwas von line 18, also dort wo steht socket.sendall(ect), dort steht aber nichts weiter.

Hat da jemand eine Idee? Und wenn das klappt, ist es möglich das ich die beiden sockets gleichzeitig parallel starten lassen kann? Damit ich nicht jedesmal jeden einzeln starten muss(also der server dann mit konstantem port).

Gruß
JonnyDamnnox
User
Beiträge: 68
Registriert: Sonntag 10. März 2013, 21:14

lol oh man, ok vergesst alles, es geht auch ohne diesen ident mist. Habs mit dem client geschafft, einfach nacheinander die eingaben hin gesendet und nicht alles auf einmal :roll:
Naja wieder was gelernt :K

Gruß
Faule Socke
User
Beiträge: 11
Registriert: Mittwoch 27. März 2013, 10:57

Ja, jedes IRC-Cmd wird mit \r\n beendet (euirc weicht allerdings interessanterweise davon ab...), du musst also jedes "einzeln" übertragen. Schau dir die IRC-Spezifikationen[1][2] an, damit lässt sich das Protokoll leicht implementieren :)

Referenzen:
[1] http://www.irchelp.org/irchelp/rfc/rfc.html
[2] http://www.ietf.org/rfc/rfc1459.txt

Hatte noch einen besseren Link dazu, finde ihn nur leider grade nicht :(

Gruß Socke
JonnyDamnnox
User
Beiträge: 68
Registriert: Sonntag 10. März 2013, 21:14

Hallo,
Also der "bot" funktioniert jetzt ganz gut. Aber muss ich die nächsten Befehle alle in diese while-schleifen schreiben? Weil dann werden die Befehle ja bei jedem ping/pong wieder ausgeführt. In diesem Fall schreibt "er" jedes mal "hi". Aber er muss ja auch ständig pong zurücksenden. Ich könnte auch wieder neue Funktionen(oder Klassen mit Methoden) definieren und ihn die Instanzen dann in der "main-whileschleife" angemessen ausführen lassen(z.b. eine Funktion die die while schleife übernimmt) aber macht man das so? Dann wird die main Funktion ja riesig, weil man alles in sie reinstopft.
Hier der code:

Code: Alles auswählen

#client der mit irc-server kontakt aufnimmt und channel1234 auf irc.iz-smart.net joined
import time
import socket
import time
from contextlib import closing

def main():
	with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock:
		print "Socket(Client)"
		host = "irc.iz-smart.net"
		port = 6667 
		PASS = "grsdg78" 
		NICK = "Testikus" 
		USER = "Testikus localhost irc.iz-smart.net :testikus" 
		sock.connect((host, port))
		sock.sendall("PASS "+PASS+"\n")
		sock.sendall("NICK "+NICK+"\n")
		sock.sendall("USER "+USER+"\n")
		join = "JOIN #channel1234 \r\n"
		print "Verbindung aufgebaut zu {0}(IP:{1}), gesendet: {2}".format(
	        host, socket.gethostbyname(host), input
		)
		while True:
			antwort = sock.recv(4096)
			print antwort
			if antwort[0:4] == "PING":
				sock.send("PONG " + antwort.split()[1] + "\n")
				time.sleep(2)
				sock.sendall(join)
				sock.sendall("PRIVMSG #channel1234 hi \r\n")
				
if __name__ == "__main__":
	main()
	

Gruß

edit/ oh man, aus irgendeinem Grund kommt er jetzt nicht mehr in den irc channel, was auch immer.
edit2/ ok jetzt scheint es zu klappen....jedenfalls bei dem code -.-
Zuletzt geändert von JonnyDamnnox am Samstag 6. April 2013, 17:58, insgesamt 1-mal geändert.
JonnyDamnnox
User
Beiträge: 68
Registriert: Sonntag 10. März 2013, 21:14

Niemand??? :-/
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Du implementierst einfach die einzelnen Reaktionen auf Nachrichten und Funktionen des Servers als Funktionen oder besser Methoden. Es gibt absolut keinen Grund dafür main() "riesig" werden zu lassen, deine main() Funktion ist ja so schon viel zu groß.
BlackJack

@JonnyDamnnox: Das der gezeigte Quelltext läuft kann ich nicht ganz glauben. Ich sehe auf Anhieb drei `NameError` die das verhindern. ;-)
JonnyDamnnox
User
Beiträge: 68
Registriert: Sonntag 10. März 2013, 21:14

@BlackJack: Habs editiert :wink:
@DasIch :

Hoi, ja also wie meinst du das? Soll ich um die main() Funktion eine Klasse "schreiben" und dann noch weitere einfügen, damit ich dann mit instanz usw Arbeiten kann. Aber wie bleibt dann die while-Schleifen erhalten? Es muss ja immer das PING vom Server beantwortet werden.

Gruß
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Die Schleife muss erhalten bleiben aber innerhalb der Schleife kannst du Funktionen und Methoden aufrufen und auch die Schleife selbst muss nicht in main() sein.
JonnyDamnnox
User
Beiträge: 68
Registriert: Sonntag 10. März 2013, 21:14

Hey ho DasIch,

Also ich habs jetzt mal komplett umgeschrieben, leider gibt es so ein paar Probleme:

Code: Alles auswählen

#client der mit irc-server kontakt aufnimmt
import time
import socket
from contextlib import closing

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

class funktion:
	
	def main(self):
		
		print "Socket(Client)"
		host = "irc.iz-smart.net"
		port = 6667 
		PASS = "7987fshd" 
		NICK = "Testikus" 
		USER = "Testikus localhost irc.iz-smart.net :Testikus" 
		sock.connect((host, port))
		sock.sendall("PASS "+PASS+"\n")
		sock.sendall("NICK "+NICK+"\n")
		sock.sendall("USER "+USER+"\n")
		print "Verbindung aufgebaut zu {0}(IP:{1})".format(
		host, socket.gethostbyname(host)
		)
		self.schleife()
			
	def schleife(self):
		while True:
			antwort = sock.recv(4096)
			join = "JOIN #testblablub \r\n"
			print antwort
			if antwort[0:4] == "PING":
				sock.sendall("PONG " + antwort.split()[1] + "\n")
				time.sleep(2)
				sock.sendall(join)
				sock.sendall("PRIVMSG #testblablub hi \r\n")
			elif antwort.split()[3] != "":
				self.reply()
	
	def pong(self):
		pass
		
	def login(self):
		pass
		
	def reply(self):
		sock.sendall("PRIVMSG #testblablub du hast was geschrieben \r\n")
		
			
ausfuehren = funktion()
ausfuehren.main()

Erstmal wird jetzt immer beim channeljoinen "du hast was geschrieben" drei mal geschrieben, sehr mirakulös(der Rest funktioniert). Dann würde ich gerne das was bei if antwort... steht in die def pong(self) Funktion umwandeln und diese dann ausführen lassen. Dazu muss ich aber auf antwort = sock.recv(4096) zugreifen, was natürlich nicht geht, weil ich es dann in der Funktion neu definieren müsste, dafür muss aber zuerst connected werden. D.h. als globale Variable gehts auch nicht, ausser ich mache connect usw auch global, was aber doof ist. Auch würde ich gern die ganzen sock. dinger in main() in eine eigene Funktion mit drei Variablen umbauen(die login Funktion). Ich hab aber Angst das dann wieder irgendwas nicht definiert ist, und in den anderen Funktionen kommt ja auch immer wieder ein sock.irgendwas vor. Aber wie krieg ich das mit dem antwort ding hin? Oder wie kriegt man es allgemein hin das wenn man auf eine Variable zugreifen will die schon in einer anderen Funktion definiert ist, aber nicht global ist?
Ich hoffe das war verständlich :?

Gruß
JonnyDamnnox
User
Beiträge: 68
Registriert: Sonntag 10. März 2013, 21:14

Alles klar ich habs, zu dumm um nachzugucken wie man sowas macht :roll:

Code: Alles auswählen

#client der mit irc-server kontakt aufnimmt
import time
import socket
from contextlib import closing

sock = closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM))

class bot:
	
	def main(self):
		
		print "Socket(Client)"
		host = "irc.iz-smart.net"
		port = 6667 
		PASS = "7987fshd" 
		NICK = "Testikus" 
		USER = "Testikus localhost irc.iz-smart.net :Testikus" 
		login(self, PASS, NICK, USER, host, port)
		print "Verbindung aufgebaut zu {0}(IP:{1})".format(
		host, socket.gethostbyname(host)
		)
		self.schleife()
			
	def schleife(self):
		while True:
			antwort = sock.recv(4096)
			join = "JOIN #testblablub \r\n"
			print antwort
			if antwort[0:4] == "PING":
				self.pong(antwort, join)
			elif antwort.split()[3] != "":
				self.reply()
	
	def pong(self, antwort, join):
		sock.sendall("PONG " + antwort.split()[1] + "\n")
		time.sleep(2)
		sock.sendall(join)
		sock.sendall("PRIVMSG #testblablub hi \r\n")
		
	def constants(self):
		pass

	def login(self, PASS, NICK, USER, host, port):
		sock.connect((host, port))
		sock.sendall("PASS "+PASS+"\n")
		sock.sendall("NICK "+NICK+"\n")
		sock.sendall("USER "+USER+"\n")
	
	def reply(self):
		sock.sendall("PRIVMSG #testblablub du hast was geschrieben \r\n")
		
			
ausfuehren = bot()
ausfuehren.main()


Jetzt würde ich gerne wissen was ich noch "wrappen"(nennt man das so? code in Funktionen packen ?, hab das schon öfters gelesen)kann. Was ist mit den ganzen Konstanten in main? Würde das Sinn machen? Was könnte ich denn noch ordnen? Und dann will ich ja weitere Befehle für den Bot als Funktionen in die while-Schleife packen. Wie kann ich eine elif-Orgie vermeiden??
Und leider schreibt er immernoch beim channel-joinen drei mal "du hast was geschrieben" :K

Gruß
:-)
Antworten