{"id":28156362,"url":"https://github.com/plietar/kvm-client","last_synced_at":"2025-05-15T07:34:31.699Z","repository":{"id":288508058,"uuid":"967998764","full_name":"plietar/kvm-client","owner":"plietar","description":null,"archived":false,"fork":false,"pushed_at":"2025-04-18T00:49:01.000Z","size":17,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-18T13:26:01.330Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/plietar.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-04-17T10:36:43.000Z","updated_at":"2025-04-18T00:49:04.000Z","dependencies_parsed_at":"2025-04-18T13:26:12.347Z","dependency_job_id":"959b9a7c-92ed-421a-831c-9a8c6e532e5e","html_url":"https://github.com/plietar/kvm-client","commit_stats":null,"previous_names":["plietar/kvm-client"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/plietar%2Fkvm-client","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/plietar%2Fkvm-client/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/plietar%2Fkvm-client/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/plietar%2Fkvm-client/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/plietar","download_url":"https://codeload.github.com/plietar/kvm-client/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254297377,"owners_count":22047484,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-05-15T07:34:07.875Z","updated_at":"2025-05-15T07:34:31.670Z","avatar_url":"https://github.com/plietar.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# A client for remote KVM\n\nThis client remotely connects to the BMC on rack-mounted server and displays\nthe server's video output locally. It also allows keystrokes to be sent to the\nserver for remote control. The BMC exists outside of the operating system and\nmain CPU, making this suitable for remote administration of the BIOS\nconfiguration and supervision of the early boot stages, before and SSH server\nis available.\n\nTypically these servers expose a web interface, from which a Java applet called\nJViewer can be run. Unfortunately the web interface uses an old TLS version,\ncausing modern browsers to refuse to connect to it.\n\nThis has only been tested on a PowerEdge C6100. Other Dell (and possibly\nnon-Dell) servers may be supported.\n\n## Usage\n### KVM mode\n\n```\nkvm-client connect 10.0.0.1 --username root --password itsme\n```\n\nOnce the client is connected to the remote machine, it will open up a console\nmirroring the machine's video output.\n\n### Proxy mode\n\n```\nkvm-client proxy 10.0.0.1 --port 8080\n```\n\nThis sets up a simple proxy on the specified port, and forwards any connection\nto the given IP address using TLSv1.0. It can be used to workaround the\nsecurity restrictions of modern browsers that refuse to connect to such an\noutdated and insecure protocol version. You can visit\n`http://localhost:8080/login.asp` to access the BMC administration page.\n\nThe proxy is very dumb and does not perform any rewritting of the responses,\nwhich makes it particularly brittle. The BMC uses absolute redirects, using\n`https://localhost:8080/...` as the destination URL and overriding the\nprotocol. Additionally, the `.jnlp` of the Java Applet includes the URL of the\nJava `.jar` files, but these will start with `https://localhost/Java/...`\n\nThe proxy does not improve the security of the connection in any way. The\nconnections between the server and the proxy still uses an outdated TLS\nversion, and the connection between the proxy and your browser uses plain HTTP.\nIt just serves as a workaround for browser restrictions.\n\n## Limitations\n\nA lot of auixiliary controls are not implemented, such as remote mounting of\nISOs, bandwidth control, mouse inputs, ...\n\nThe video feed packet format suggests that RC4 encryption may optionally be\nused. Since I did not encounter any encrypted packets, I did not implement\ndecryption.\n\nThe video feed decoder only supports one of two compression modes. If the video\ncard uses the unsupported mode, the client will crash. It's not clear when\nexactly does the card switch modes. In my experience, WebBIOS, GRUB and Wayland\ncompositors cause this to happen.\n\nThere exists [an open source decoder written in C][aspeed_codec], targetting\nWebAssembly for the other compression mode. It should be possible to port it to\nPython, or to link to the relevant parts of the C code.\n\n[aspeed_codec]: https://github.com/AspeedTech-BMC/aspeed_codec\n\n## Protocol details\n\nThe BMC has its own IP address, running an HTTP server. In addition to basic\nsensor reading and control over chassis power, the web page hosts a Java\napplet that can act as a remote video console.\n\nThe Java Applet connects to the BMC over port 7578. The protocol uses a simple\n[type-length-value][TLV] style encoding. The 7-byte header is composed of the\ntype (1 byte), the length (4 bytes, litte endian) and two additional unknown\nbytes. The header is immediately followed by the payload. The length field only\nincludes the payload bytes, not the 7 header bytes.\n\n[TLV]: https://en.wikipedia.org/wiki/Type%E2%80%93length%E2%80%93value\n\n| Type |   Direction   | Description | Payload |\n|------|---------------|-------------|---------|\n| 0x23 | Client to BMC | Authentication request | ASCII-encoded authentication token |\n| 0x24 | BMC to Client | Authentication result  | A single byte, 1 for success and 0 for a failure |\n| 0x05 | BMC to Client | Video feed | See below |\n| 0x05 | Client to BMC | Keyboard and Mouse input | See below |\n\n### Video feed\n\nAs soon as the client is authenticated, the BMC will start sending out regular\nvideo packets. Each video packet starts with its own header which includes a\nlot of information, including the display resolution, frame number,\nencryptions, ...\n\nThe rest of the packet is a bit stream. Each block of 4 bytes should be read as\na little-endian word (least significant byte first). From that word, bitfields\nof varying lengths may be read starting with the most-significant bits. A\nbitfield may straddle two bytes or even two words.\n\nPackets only include parts of the image that have changed. The change described\nby the packet should be applies to the in-memory frame buffer maintained by the\nreceiver. The bitstreams describes a sequence of groups, each group\nrepresenting an 8 by 8 grid of pixels.\n\nEach group may optionally include its coordinates. If not specified, the\ncoordinates increment automatically from the previous received group.\n\nThere are two broad compression modes:\n\n- In the \"basic\" mode, each group defines a palette of 2^k colours, where k\n    ranges from 0 to 2, inclusive. Each of the 64 pixels in the group is\n    then represented as k bits, which are used to index into the palette.\n    The colours are represented in [YUV-space][YUV], using one byte per\n    component.\n\n- The secondary mode is much more complicated and seems to be inspired from\n    JPEG encoding. It uses Huffman encoding and discrete cosine transforms\n    (DCT).\n\n[YUV]: https://en.wikipedia.org/wiki/Y%E2%80%B2UV\n\n### Keyboard and Mouse\n\nTBD\n\n## Future directions\n\nIdeally I would like to make this a web-based client instead of a Python\ndesktop application. From one instance of the server one should be able to\naccess any number of machines. The server can be hosted on a small device (eg.\na Raspberry Pi) located on the BMCs network.\n\nThe video decoding could either remain implemented in Python server-side, and\nre-encoded into a standard video format that can easily be displayed in a\nmodern browser, or the decoder could be reimplemented in a client friendly\nlanguage (JavaScript or compiled to WebAssembly). The server would merely act\nas a tunnel between a WebSocket and a TCP connection to the BMC.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fplietar%2Fkvm-client","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fplietar%2Fkvm-client","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fplietar%2Fkvm-client/lists"}