Repository: matildah/hellcat
Branch: master
Commit: 59cdb8b9e765
Files: 8
Total size: 13.7 KB
Directory structure:
gitextract_aud_kfbm/
├── .gitignore
├── LICENSE
├── Makefile
├── README.md
└── src/
├── net.c
├── net.h
├── recv.c
└── send.c
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
# Object files
*.o
*.ko
*.obj
*.elf
# Libraries
*.lib
*.a
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
a.out
hellsend
hellrecv
================================================
FILE: LICENSE
================================================
The MIT License (MIT)
Copyright (c) 2014 Kia <>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: Makefile
================================================
CC=clang
CFLAGS=-Wall -ggdb -Weverything # -fsanitize=integer -fsanitize=address -fsanitize=undefined
all: hellrecv hellsend
%.o : %.c
$(CC) -c $(CFLAGS) $< -o $@
hellrecv: src/recv.o src/net.o
$(CC) $(CFLAGS) -o $@ $^
hellsend: src/send.o src/net.o
$(CC) $(CFLAGS) -o $@ $^
clean:
rm -f hellsend hellrecv src/*.o
================================================
FILE: README.md
================================================
hellcat
=======
netcat that takes unfair advantage of traffic shaping systems that apply a
higher rate limit (more bandwidth) for the first k bytes (or t seconds, configs
vary) of a TCP connection than for the rest of the connection. This is usually
done to make web browsing feel faster while still throttling big downloads. In
order to exploit this behavior, we send k bytes over a TCP connection, then we
close it and then create another one. That way, data transfer always happens in
the initial regime (the one with a higher rate limit), increasing the average
rate of data transfer.
You *need* to give the same chunksize value to the receiving end and the
transmitting end otherwise you will have incomplete transfer.
TODO: transfer the chunksize over the control connection from the sender to the
receiver so you don't have to specify it once on each end.
================================================
FILE: src/net.c
================================================
/* copyright (c) 2014 Kia <> */
/* this file contains functions that make dealing with the network a bit
easier */
#include "net.h"
/* this function just runs send(2) in a loop until the entire buffer is sent or
an error happens */
ssize_t send_all(int socket, const uint8_t *buffer, size_t length, int flag)
{
size_t bytes_sent = 0;
size_t bytes_unsent = length;
ssize_t sent;
while (bytes_sent < length)
{
sent = send(socket, buffer + bytes_sent, bytes_unsent, flag);
if (sent == -1)
return -1;
bytes_sent += (size_t)sent;
bytes_unsent -= (size_t)sent;
}
return (ssize_t)bytes_sent;
}
/* just runs recv(2) in a loop until an error happens or our peer shuts down
the connection */
ssize_t recv_all(int socket, uint8_t *buffer, size_t length, int flag)
{
size_t bytes_received = 0;
size_t bytes_unreceived = length;
ssize_t received;
while (bytes_received < length)
{
received = recv(socket, buffer + bytes_received, bytes_unreceived, flag);
if (received == -1)
return -1;
if (received == 0)
return 0;
bytes_received += (size_t)received;
bytes_unreceived -= (size_t)received;
}
return (ssize_t)bytes_received;
}
ssize_t read_all(int fd, uint8_t *buffer, size_t length)
{
size_t bytes_received = 0;
size_t bytes_unreceived = length;
ssize_t received;
while (bytes_received < length)
{
received = read(fd, buffer + bytes_received, bytes_unreceived);
if (received == -1)
return -1;
if (received == 0)
return (ssize_t) bytes_received;
bytes_received += (size_t)received;
bytes_unreceived -= (size_t)received;
}
return (ssize_t)bytes_received;
}
ssize_t write_all(int fd, const uint8_t *buffer, size_t count)
{
size_t bytes_sent = 0;
size_t bytes_unsent = count;
ssize_t sent;
while (bytes_sent < count)
{
sent = write(fd, buffer + bytes_sent, bytes_unsent);
if (sent == -1)
return -1;
bytes_sent += (size_t)sent;
bytes_unsent -= (size_t)sent;
}
return (ssize_t)bytes_sent;
}
int make_socket(char *node, char *port) {
int rval, fd = -1;
struct addrinfo hints;
struct addrinfo *result, *rp;
/* let's do fun stuff with getaddrinfo now */
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC; /* either ipv4 or ipv6, we don't care */
hints.ai_socktype = SOCK_STREAM; /* TCP */
hints.ai_flags = 0;
hints.ai_protocol = 0;
rval = getaddrinfo(node, port, &hints, &result);
if (rval != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rval));
exit(1);
}
/* now we iterate over the lists of results that getaddrinfo returned
until we can successfully make a socket and connect with it */
for (rp = result; rp != NULL; rp = rp->ai_next) {
fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (fd == -1) {
/* the socket making failed, so we need to do a different
address */
continue;
}
/* we made a socket, now we try to connect */
if (connect(fd, rp->ai_addr, rp->ai_addrlen) != -1) {
break; /* we successfully connected, let's exit this loop */
}
close(fd); /* making the socket worked but connect() failed so we
close this socket */
}
if (rp == NULL) { /* no address worked */
fprintf(stderr, "Could not connect to %s:%s\n",node, port);
exit(1);
}
freeaddrinfo(result);
return fd;
}
int make_listener(char *port)
{
int rval, fd = -1;
struct addrinfo hints;
struct addrinfo *result, *rp;
int optval = 1;
/* let's do fun stuff with getaddrinfo now */
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC; /* either ipv4 or ipv6, we don't care */
hints.ai_socktype = SOCK_STREAM; /* TCP */
hints.ai_flags = AI_PASSIVE;
hints.ai_protocol = 0;
rval = getaddrinfo(NULL, port, &hints, &result);
if (rval != 0)
{
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rval));
exit(1);
}
/* now we iterate over the lists of results that getaddrinfo returned
until we can successfully make a socket and connect with it */
for (rp = result; rp != NULL; rp = rp->ai_next)
{
fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval);
if (fd == -1)
{
/* the socket making failed, so we need to do a different
address */
continue;
}
/* we made a socket, now we try to bind */
if (bind(fd, rp->ai_addr, rp->ai_addrlen) != -1)
{
break; /* we successfully bound, let's exit this loop */
}
perror("bind bind bind");
close(fd); /* making the socket worked but bind() failed so we
close this socket */
}
if (rp == NULL) /* no address worked */
{
perror("bind");
fprintf(stderr, "Could not bind to %s\n", port);
exit(1);
}
freeaddrinfo(result);
listen(fd, 1);
return fd;
}
================================================
FILE: src/net.h
================================================
/* copyright (c) 2013 Kia <> */
#define _GNU_SOURCE
#include <fcntl.h>
#include <stdint.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <errno.h>
ssize_t send_all(int socket, const uint8_t *buffer, size_t length, int flag);
ssize_t recv_all(int socket, uint8_t *buffer, size_t length, int flag);
ssize_t read_all(int fd, uint8_t *buffer, size_t length);
ssize_t write_all(int fd, const uint8_t *buffer, size_t count);
int make_socket(char *node, char *port);
int make_listener(char *port);
#define CONT 0xcc
#define DONE 0xdd
================================================
FILE: src/recv.c
================================================
/* copyright (c) 2014 Kia <> */
/* the functions in this file handle the whole "receiving" thing */
#include "net.h"
#include <sys/time.h>
int main(int argc, char* argv[])
{
int datafd, controlfd, control_listener, data_listener, listening;
ssize_t rval, rval_send;
uint8_t statusbyte, cont = CONT;
uint8_t *buf;
size_t bufsize, totalsize = 0;
struct timeval start, end;
float elapsed;
if ((argc != 5) && (argc != 4)) {
fprintf(stderr, "usage: %s chunksize dataport controlport [host]\nchunksize is in bytes\n", argv[0]);
exit(10);
}
if (argc == 4) {
listening = 1;
} else {
listening = 0;
}
bufsize = (size_t) atol(argv[1]);
buf = malloc(bufsize);
assert(buf != NULL);
if (listening == 0) {
controlfd = make_socket(argv[4], argv[3]);
} else {
control_listener = make_listener(argv[3]);
data_listener = make_listener(argv[2]);
controlfd = accept(control_listener, NULL, NULL);
if (controlfd == -1) {
perror("accept on control port");
exit(1);
}
}
sleep(1);
gettimeofday(&start, NULL);
while (1) {
rval = read(controlfd, &statusbyte, 1);
if (rval != 1) {
perror("read on controlfd");
exit(1);
}
if (statusbyte == DONE) {
fprintf(stderr, "received DONE\n");
gettimeofday(&end, NULL);
elapsed = (end.tv_sec - start.tv_sec) + (end.tv_usec - start.tv_usec) / 1000000;
fprintf(stderr, "transferred %zu bytes in %.3f seconds\n", totalsize, elapsed);
break;
}
assert (statusbyte == CONT);
if (listening == 0) {
datafd = make_socket(argv[4], argv[2]);
} else {
datafd = accept(data_listener, NULL, NULL);
if (datafd == -1) {
perror("accept on data port");
exit(1);
}
}
rval = read_all(datafd, buf, bufsize);
if (rval == -1) {
perror("read on datafd");
exit(1);
}
if (rval == 0) { /* eof on datafd */
fprintf(stderr, "unexpected EOF on datafd\n");
exit(1);
}
rval_send = write_all(1, buf, (size_t)rval);
if (rval_send != rval) {
perror("write on stdout");
exit(1);
}
if (listening == 1) {
rval = write(controlfd, &cont, 1);
if (rval != 1) {
perror("write on controlfd");
exit(1);
}
}
totalsize += (size_t) rval;
close(datafd);
}
close(controlfd);
return 0;
}
================================================
FILE: src/send.c
================================================
/* copyright (c) 2014 Kia <> */
/* the functions in this file handle the whole "sending data out" thing */
#include "net.h"
int main(int argc, char* argv[])
{
int data_listener, controlfd, control_listener, listening, datafd = -1;
ssize_t rval, numbytes, rval_send;
uint8_t *buf;
size_t bufsize;
uint8_t cont = CONT;
uint8_t done = DONE;
uint8_t statusbyte;
if ((argc != 4) && (argc != 5)) {
fprintf(stderr, "usage: %s chunksize dataport controlport [host]\nchunksize is in bytes\n", argv[0]);
exit(10);
}
if (argc == 4) {
listening = 1;
} else {
listening = 0;
}
bufsize = (size_t) atol(argv[1]);
buf = malloc(bufsize);
assert(buf != NULL);
if (listening == 1) {
control_listener = make_listener(argv[3]);
data_listener = make_listener(argv[2]);
controlfd = accept(control_listener, NULL, NULL);
if (controlfd == -1) {
perror("accept on control port");
exit(1);
}
} else {
controlfd = make_socket(argv[4], argv[3]);
}
while (1) {
numbytes = read_all(0, buf, bufsize);
if (numbytes == -1) {
perror("read on stdin");
exit(1);
}
if (numbytes == 0) { /* eof on stdin */
rval = write(controlfd, &done, 1);
if (rval != 1) {
perror("write on controlfd (while exiting, which makes this even more humiliating)");
exit(1);
}
break;
}
rval = write(controlfd, &cont, 1);
if (rval != 1) {
perror("write on controlfd");
exit(1);
}
if (listening == 1) {
datafd = accept(data_listener, NULL, NULL);
} else {
datafd = make_socket(argv[4], argv[2]);
}
if (datafd == -1) {
perror("data port connect / accept failure?");
exit(1);
}
rval_send = write_all(datafd, buf, (size_t) numbytes);
if (rval_send != numbytes) {
perror("incomplete write on datafd");
exit(1);
}
rval = close(datafd);
if (rval != 0) {
perror("close");
fprintf(stderr,"close returned %d\n", rval);
exit(1);
}
if (listening == 0) {
rval = read(controlfd, &statusbyte, 1);
if (rval != 1) {
perror("read on controlfd");
fprintf(stderr, "%d\n", rval);
exit(1);
}
assert(statusbyte == CONT);
}
}
free(buf);
if (datafd != -1) {
close(datafd);
}
close(controlfd);
return 0;
}
gitextract_aud_kfbm/
├── .gitignore
├── LICENSE
├── Makefile
├── README.md
└── src/
├── net.c
├── net.h
├── recv.c
└── send.c
SYMBOL INDEX (8 symbols across 3 files)
FILE: src/net.c
function send_all (line 9) | ssize_t send_all(int socket, const uint8_t *buffer, size_t length, int f...
function recv_all (line 31) | ssize_t recv_all(int socket, uint8_t *buffer, size_t length, int flag)
function read_all (line 54) | ssize_t read_all(int fd, uint8_t *buffer, size_t length)
function write_all (line 76) | ssize_t write_all(int fd, const uint8_t *buffer, size_t count)
function make_socket (line 96) | int make_socket(char *node, char *port) {
function make_listener (line 142) | int make_listener(char *port)
FILE: src/recv.c
function main (line 10) | int main(int argc, char* argv[])
FILE: src/send.c
function main (line 10) | int main(int argc, char* argv[])
Condensed preview — 8 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (15K chars).
[
{
"path": ".gitignore",
"chars": 203,
"preview": "# Object files\n*.o\n*.ko\n*.obj\n*.elf\n\n# Libraries\n*.lib\n*.a\n\n# Shared objects (inc. Windows DLLs)\n*.dll\n*.so\n*.so.*\n*.dyl"
},
{
"path": "LICENSE",
"chars": 1073,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2014 Kia <>\n\nPermission is hereby granted, free of charge, to any person obtaining "
},
{
"path": "Makefile",
"chars": 323,
"preview": "CC=clang\nCFLAGS=-Wall -ggdb -Weverything # -fsanitize=integer -fsanitize=address -fsanitize=undefined\n\nall: hellrecv hel"
},
{
"path": "README.md",
"chars": 867,
"preview": "hellcat\n=======\n\nnetcat that takes unfair advantage of traffic shaping systems that apply a\nhigher rate limit (more band"
},
{
"path": "src/net.c",
"chars": 5385,
"preview": "/* copyright (c) 2014 Kia <> */\n/* this file contains functions that make dealing with the network a bit\n easier */\n#i"
},
{
"path": "src/net.h",
"chars": 681,
"preview": "/* copyright (c) 2013 Kia <> */\n\n#define _GNU_SOURCE\n#include <fcntl.h>\n#include <stdint.h>\n#include <stdlib.h>\n#include"
},
{
"path": "src/recv.c",
"chars": 2748,
"preview": "/* copyright (c) 2014 Kia <> */\n\n/* the functions in this file handle the whole \"receiving\" thing */\n\n#include \"net.h\"\n#"
},
{
"path": "src/send.c",
"chars": 2760,
"preview": "/* copyright (c) 2014 Kia <> */\n\n/* the functions in this file handle the whole \"sending data out\" thing */\n\n#include \"n"
}
]
About this extraction
This page contains the full source code of the matildah/hellcat GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 8 files (13.7 KB), approximately 3.8k tokens, and a symbol index with 8 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.