Coder Social home page Coder Social logo

libtelnet's People

Contributors

charlesunixpro avatar egtra avatar endgame avatar eugpermar avatar floatinghotpot avatar hefloryd avatar jhersh avatar katef avatar marado avatar mhei avatar patrickdepinguin avatar pimlie avatar ryukojiro avatar seanmiddleditch avatar shea690901 avatar skissane avatar slcasner avatar thefallentree avatar weckx avatar xiaoxiang781216 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

libtelnet's Issues

telnet-client - Linux buffering issue

It looks like the telnet-client example does not flush the output buffer in the TELNET_EV_DATA section of it's event handler. On Linux, at least, this causes an issue as the stream is buffered and not written reliably until a newline is hit.

This means you won't see login prompts and such that do not end in newlines.

I fixed this in my local copy by adding a fflush(stdout) right after the printf, though I suppose you could also fix it by disabling buffering. I'm reporting it here because I thought you might want to change it in your example code.

Other than that: GREAT library. This seems to be exactly the kind of comprehensive implementation that I was looking for to replace some hacked together code I wrote to handle telnet connections in my own app. THANK YOU for sharing the code.

Simplify API

I was trying to use libtelnet for a program that needs to send messages to a telnet server (a robot), but using it is very complicated. And the example telnet_client.c is too complicated too to adapt it. I think the libtelnet API could be made a lot simpler.

I would expect of a library like libtelnet to already provide me with a working socket, instead of me having to open one and pass it to the library.

I don't see any benefit in writing the code to get the socket outside of libtelnet. It's always going to be the same. Repeating the same code for every program that uses the library isn't good IMHO.

Couldn't this function be used inside libtelnet to provide a socket? :

int	alx_tcp_client_open	(const char *restrict server_addr,
				 const char *restrict server_port)
{
	struct protoent	*tcp;
	int		sd;
	struct addrinfo	hint = {0};
	struct addrinfo	*addrs;
	int		status;

	tcp	= getprotobyname("tcp");
	if (!tcp)
		return	-EINVAL;
	hint.ai_family		= AF_UNSPEC;
	hint.ai_socktype	= SOCK_STREAM;
	hint.ai_protocol	= tcp->p_proto;
	status	= getaddrinfo(server_addr, server_port, &hint, &addrs);
	if (status)
		return	-labs(status);

	for (struct addrinfo *ad = addrs; ad; ad = ad->ai_next) {
		sd = socket(ad->ai_family, ad->ai_socktype, ad->ai_protocol);
		if (sd < 0)
			continue;
		if (connect(sd, ad->ai_addr, ad->ai_addrlen))
			goto try_next;
		break;
try_next:
		close(sd);
		sd = -1;
	}
	freeaddrinfo(addrs);

	if (sd < 0)
		return	-errno;
	return	sd;
}

I could write that API myself if I understood how libtelnet works, but it's too complicated for me.

I think the library needs some abstraction layers. For example a layer that handles all the TCP part, and then a simple layer that adds the TELNET part on top of it.

Allocation optimization in _set_rfc1143() is wrong.

The comments in _set_rfc1143() indicate that option state slots are allocated in groups of four to reduce realloc() calls, but the code never uses the three extra slots.

The code incorrectly assumes that if the entry is not found, a relloc is needed. The "search for entry" loop should break if the telopt field is 0 (indication end of list), and the realloc should only occur if "i" is less than "q_size".

This error causes excessive calls to realloc and wasted space in telnet->q.

CMake

Upgrade to a modern packaging-friendly CMake build system.

sonames and versioning

Begin using proper sonames (on ELF platforms) and name versioning for API/ABI breakages.

libtelnet.so.1
libtelnet-1/telnet.h
libtelnet-1.dll

etc.

undefined behaviour - missing va_end() calls

I did run the code through cppcheck static analysis - it found 2 errors.

[libtelnet.c:1387]: (error) va_list 'va2' was opened but not closed by va_end().
[libtelnet.c:1457]: (error) va_list 'va2' was opened but not closed by va_end().

Error branches in functions telnet_vprintf() and telnet_raw_vprintf() do not call va_end() for the valist va2 - this is undefined behaviour.

Compatibility with telnet client of Mac OS X

  • Using telnet client of libtelnet, when I send 2 UTF8 Chinese word "火锅", it send "<0xE7><0x81><0xAB><0xE9><0x94><0x85>", which can be correctly printed as "火锅".
  • Using telnet of Mac to connect to telnet-proxy, when I type the same word, it sends "<0x67><0x01><0x2B><0x69><0x05>", which cannot be printed correctly.

Why? Is there any encoding in telnet of Mac, which is not handled by libtelnet?

Note: I use telnet-proxy to inspect the network traffic.

Shouldn't telnet_send() do CR-NUL and CR-LF translations?

Why is the implementation of EOL translation only in vprintf() and not in telnet_send()? The escaping of IAC is in both places. In my local copy I have merged the EOL code from vprintf() into telnet_send(). This matters for my application because libtelnet interfaces at a lower level where upper levels have already done the printf work.

Repeated toggling of TELNET_TELOPT_ECHO not working

On a telnet server I'm writing, I'm seeing an issue where after the following sequence of calls:

telnet_negotiate(descriptor->telnet, TELNET_WILL, TELNET_TELOPT_ECHO);
telnet_negotiate(descriptor->telnet, TELNET_WONT, TELNET_TELOPT_ECHO);

Further attempts to enable TELNET_TELOPT_ECHO don't work: the IAC sequence is never sent out.

(The code is from MudCore: https://github.com/endgame/MudCore and the following boot.lua generates this behaviour: )

function mud.descriptor.on_open(d)
  d:will_echo(true)
  mud.descriptor.read()
  d:will_echo(false)
  mud.descriptor.read()
  d:will_echo(true)
  mud.descriptor.read()
  d:will_echo(false)
  mud.descriptor.read()
end

If you poke around the MudCore source, you'll see that descriptor_will_echo (src/descriptor.c) tries to track the echoing state and avoid redundant calls to telnet_negotiate. Even if check is commented out (causing telnet_negotiate to be called unconditionally), I still see this behaviour.

fluffos

https://github.com/fluffos/fluffos using libtelnet,

when using OSX telnet client to connect the server,
it will strip UTF-8 character High byte to ansi char.

Using Linux/Windows telnet client, everything is fine.

telnet clinet

the exmaple seens to be telnet server, how can I use the lib to create a telnet client? Can you show some exmaples please?

Tag 0.22?

Ahoy, it's been quite some time since 0.21's release. Would you consider pushing a new tag? This is particularly helpful for me, as I pull libtelnet into my project using CocoaPods and I'd much rather point to a tag (rather than a commit). Thanks!

Deal with the "FIXME" on README

This issue is being created just so this doesn't get forgotten.

README has a section on how to integrate libtelnet with some MUD code bases, but that is still unwritten.

document for TELNET_EV_TTYPE is missng

relevant code:

  ev.type = TELNET_EV_TTYPE;
      ev.ttype.cmd = TELNET_TTYPE_IS;
      ev.ttype.name = name;
      telnet->eh(telnet, &ev, telnet->ud);

      /* clean up */
      free(name);
    } else {
      ev.type = TELNET_EV_TTYPE;
      ev.ttype.cmd = TELNET_TTYPE_SEND;
      ev.ttype.name = 0;
      telnet->eh(telnet, &ev, telnet->ud);

Simple client that only talks

I would like to create a simple client that only logs to the server ([email protected]:23 - no password) and sends messages such as const char *msg = "exe\n";.

I don't have any experience using telnet (some experience but not much using tcp sockets).

I tried to read the header libtelnet.h to see how I can do that, but I didn't know which options I had to use. I also don't know how to tell the library the info of the server (user: as; ip: 192.168.0.1; port: 23).

What functions and options should I use for this?

Telnet automation

/*

  • Sean Middleditch
  • [email protected]
    *
  • The author or authors of this code dedicate any and all copyright interest
  • in this code to the public domain. We make this dedication for the benefit
  • of the public at large and to the detriment of our heirs and successors. We
  • intend this dedication to be an overt act of relinquishment in perpetuity of
  • all present and future rights to this code under copyright law.
    */

if !defined(_POSIX_SOURCE)

define _POSIX_SOURCE

endif

if !defined(_BSD_SOURCE)

define _BSD_SOURCE

endif

include <sys/types.h>

include <sys/socket.h>

include <netinet/in.h>

include <arpa/inet.h>

include <netdb.h>

include <poll.h>

include <errno.h>

include <stdio.h>

include <string.h>

include <stdlib.h>

include <ctype.h>

include <termios.h>

include <unistd.h>

include <fcntl.h>

ifdef HAVE_ZLIB

include "zlib.h"

endif

include "libtelnet.h"

static char* commands[256];
static int num_commands = 0;
static struct termios orig_tios;
static telnet_t *telnet;
static int do_echo;

static char pass[] = "mypassword\n";

static const telnet_telopt_t telopts[] = {
{ TELNET_TELOPT_ECHO, TELNET_WONT, TELNET_DO },
{ TELNET_TELOPT_TTYPE, TELNET_WILL, TELNET_DONT },
{ TELNET_TELOPT_COMPRESS2, TELNET_WONT, TELNET_DO },
{ TELNET_TELOPT_MSSP, TELNET_WONT, TELNET_DO },
{ -1, 0, 0 }
};

static void _cleanup(void) {
tcsetattr(STDOUT_FILENO, TCSADRAIN, &orig_tios);
}

static void _input(char *buffer, int size) {
static char crlf[] = { '\r', '\n' };
int i;

for (i = 0; i != size; ++i) {
    /* if we got a CR or LF, replace with CRLF
     * NOTE that usually you'd get a CR in UNIX, but in raw
     * mode we get LF instead (not sure why)
     */
    if (buffer[i] == '\r' || buffer[i] == '\n') {
        if (do_echo)
            printf("\r\n");
        telnet_send(telnet, crlf, 2);
    } else {
        if (do_echo)
            putchar(buffer[i]);
        telnet_send(telnet, buffer + i, 1);
    }
}
fflush(stdout);

}

static void answer(int size, char* buf)
{
unsigned char* pch = NULL;
static int cmd = 0;
buf[size] = 0;

if (((pch = strstr(buf, "ogin: ")) != NULL) && buf[size-2] == ':')
{
    _input("root\n", 5);

}
else if ((pch = strstr(buf, "assword: ")) != NULL)
{
    _input(pass, strlen(pass)); 
}
else if ((pch = strstr(buf, "#")) != NULL)
{   
    sleep(1);
    if (cmd < num_commands)
    {
        _input(commands[cmd], strlen(commands[cmd]));
        cmd++;
    }

}

}

static void _send(int sock, const char *buffer, size_t size) {
int rs;

/* send data */
while (size > 0) {
    if ((rs = send(sock, buffer, size, 0)) == -1) {
        fprintf(stderr, "send() failed: %s\n", strerror(errno));
        exit(1);
    } else if (rs == 0) {
        fprintf(stderr, "send() unexpectedly returned 0\n");
        exit(1);
    }

    /* update pointer and size to see if we've got more to send */
    buffer += rs;
    size -= rs;
}

}

static void _event_handler(telnet_t telnet, telnet_event_t *ev, void *user_data) {
int sock = *(int
)user_data;

switch (ev->type) {
/* data received */
case TELNET_EV_DATA:
    printf("%.*s", (int)ev->data.size, ev->data.buffer);
    answer((int)ev->data.size, ev->data.buffer);
    break;
/* data must be sent */
case TELNET_EV_SEND:
    _send(sock, ev->data.buffer, ev->data.size);
    break;
/* request to enable remote feature (or receipt) */
case TELNET_EV_WILL:
    /* we'll agree to turn off our echo if server wants us to stop */
    if (ev->neg.telopt == TELNET_TELOPT_ECHO)
        do_echo = 0;
    break;
/* notification of disabling remote feature (or receipt) */
case TELNET_EV_WONT:
    if (ev->neg.telopt == TELNET_TELOPT_ECHO)
        do_echo = 1;
    break;
/* request to enable local feature (or receipt) */
case TELNET_EV_DO:
    break;
/* demand to disable local feature (or receipt) */
case TELNET_EV_DONT:
    break;
/* respond to TTYPE commands */
case TELNET_EV_TTYPE:
    /* respond with our terminal type, if requested */
    if (ev->ttype.cmd == TELNET_TTYPE_SEND) {
        telnet_ttype_is(telnet, getenv("TERM"));
    }
    break;
/* respond to particular subnegotiations */
case TELNET_EV_SUBNEGOTIATION:
    break;
/* error */
case TELNET_EV_ERROR:
    fprintf(stderr, "ERROR: %s\n", ev->error.msg);
    exit(1);
default:
    /* ignore */
    break;
}

}

int load_commands(char* cmds_file, char* cmds[])
{
char str[512];
int i = 0;
FILE *fp;

fp = fopen(cmds_file, "r");
if (!fp) return 0; // bail out if file not found
while (fgets(str,sizeof(str),fp) != NULL)
{
  // strip trailing '\n' if it exists
  int len = strlen(str);
  if (str[len-1] != '\n') 
  {
      len++;
      str[len] = 0;
      str[len-1] = '\n';
  }

  cmds[i] = malloc(len);
  strcpy(cmds[i], str);
  i++;
}
fclose(fp);
return i;

}

int main(int argc, char **argv) {
char buffer[512];
int rs, i;
int sock;
struct sockaddr_in addr;
struct pollfd pfd[2];
struct addrinfo *ai;
struct addrinfo hints;
struct termios tios;

/* check usage */
if (argc != 2) {
    fprintf(stderr, "Usage:\n ./telnet-client <host>\n");
    return 1;
}

num_commands = load_commands("cmds.txt", commands);

printf("Will send %d commands\n", num_commands);

/* look up server host */
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if ((rs = getaddrinfo(argv[1],"23", &hints, &ai)) != 0) {
    fprintf(stderr, "getaddrinfo() failed for %s: %s\n", argv[1],
            gai_strerror(rs));
    return 1;
}

/* create server socket */
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
    fprintf(stderr, "socket() failed: %s\n", strerror(errno));
    return 1;
}

/* bind server socket */
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
    fprintf(stderr, "bind() failed: %s\n", strerror(errno));
    return 1;
}

/* connect */
if (connect(sock, ai->ai_addr, ai->ai_addrlen) == -1) {
    fprintf(stderr, "server() failed: %s\n", strerror(errno));
    return 1;
}

/* free address lookup info */
freeaddrinfo(ai);

/* get current terminal settings, set raw mode, make sure we
 * register atexit handler to restore terminal settings
 */
tcgetattr(STDOUT_FILENO, &orig_tios);
atexit(_cleanup);
tios = orig_tios;
cfmakeraw(&tios);
tcsetattr(STDOUT_FILENO, TCSADRAIN, &tios);

/* set input echoing on by default */
do_echo = 1;

/* initialize telnet box */
telnet = telnet_init(telopts, _event_handler, 0, &sock);

/* initialize poll descriptors */
memset(pfd, 0, sizeof(pfd));
pfd[0].fd = STDIN_FILENO;
pfd[0].events = POLLIN;
pfd[1].fd = sock;
pfd[1].events = POLLIN;

/* loop while both connections are open */
while (poll(pfd, 2, -1) != -1) {

    /* read from client */
    if (pfd[1].revents & POLLIN) {
        if ((rs = recv(sock, buffer, sizeof(buffer), 0)) > 0) {
            telnet_recv(telnet, buffer, rs);
        } else if (rs == 0) {
            break;
        } else {
            fprintf(stderr, "recv(client) failed: %s\n",
                    strerror(errno));
            exit(1);
        }
    }
}

/* clean up */
telnet_free(telnet);
close(sock);

return 0;

}

Interpreting the tests

Hey! I just wanted to say thank you for creating this repo. Is there any chance I could get some help interpreting how the tests should be implemented?

Context: I'm compiling this library to web assembly using emscripten for JavaScript developers and wrapping the functions in a Telnet class so that it can be used easily.

See: https://github.com/jtenner/libtelnet-ts

Just need to implement the tests manually using JavaScript, but I am having a hard time understanding how the tests are formatted.

Thank you very much for all this work.

Cannot handle multiple logs

I am using telnet to send logs to a client and the library is causing a crash whenever there are a lot of loglines to send. I am using telnet_vprintf(). Is there any way to increase the queue size if there is any? Also is it possible to use UDP here, as sockets are managed by user only. I know telnet is TCP based but its slow for my use case.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.