From 1eccc163c18c03c3033ae31c9099bc3d6a53b8ce Mon Sep 17 00:00:00 2001 From: "Adonay Felipe Nogueira (http://libreplanet.org/wiki/User:Adfeno)" Date: Sun, 7 Jun 2026 20:06:55 -0300 Subject: [PATCH] Add missing copyrights, use rnet_try_recv and new protoocol for 2026 * AUTHORS: Add adfeno. * decfile.c (Copyright): Idem. * decfile.h (Copyright): Idem. * doc/FORMATO: Use names from decfile.c and .h. [exerc <= 2025]: Keep old protocol [exerc >= 2026]: New format that authorizes DEC files to be sent. * NEWS: Update features. * rnet_encode.c (Copyright): Add adfeno, update lxoliva. * rnet_encode.h (Copyright): Idem. * rnet_message.c (Copyright): Update lxoliva. * rnetclient.c (rnet_try_recv): New function. (rnet_recv): Use rnet_try_recv instead of gnutls_record_recv. For exerc greater or equal than 2026, add note for different len and adjust it accordingly. * t-parse.c (Copyright): Add adfeno. --- AUTHORS | 1 + NEWS | 9 ++++++ decfile.c | 1 + decfile.h | 1 + doc/FORMATO | 77 ++++++++++++++++++++++++++++---------------- rnet_encode.c | 4 ++- rnet_encode.h | 3 ++ rnet_message.c | 3 +- rnetclient.c | 87 +++++++++++++++++++++++++++++++++++--------------- t-parse.c | 1 + 10 files changed, 132 insertions(+), 55 deletions(-) diff --git a/AUTHORS b/AUTHORS index 60ef3ab..c5d823c 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,3 +1,4 @@ Thadeu Lima de Souza Cascardo Alexandre Oliva Sergio Durigan Junior +Adonay Felipe Nogueira (http://libreplanet.org/wiki/User:Adfeno) \ No newline at end of file diff --git a/NEWS b/NEWS index e862262..205d9eb 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,12 @@ += ??? = + +Add 2026. +For 2026 and above, fix error when reading server response after sending header/summary. +By default, use same client version as reference. +Use DEC's MAC address as connection MAC. +Get and send connection's IP and port. +Add some verbose messages to ease debugging. + = 2017.1 = Allow server to be specified. diff --git a/decfile.c b/decfile.c index 6d4f694..d952e64 100644 --- a/decfile.c +++ b/decfile.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2012-2014 Thadeu Lima de Souza Cascardo * Copyright (C) 2014 Alexandre Oliva + * Copyright (C) 2026 Adonay Felipe Nogueira (http://libreplanet.org/wiki/User:Adfeno) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/decfile.h b/decfile.h index 159f694..664004e 100644 --- a/decfile.h +++ b/decfile.h @@ -1,6 +1,7 @@ /* * Copyright (C) 2012-2014 Thadeu Lima de Souza Cascardo * Copyright (C) 2014 Alexandre Oliva + * Copyright (C) 2026 Adonay Felipe Nogueira (http://libreplanet.org/wiki/User:Adfeno) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/doc/FORMATO b/doc/FORMATO index 65f3282..86ecd58 100644 --- a/doc/FORMATO +++ b/doc/FORMATO @@ -3,7 +3,7 @@ S: "E" C: "00000000000000" (14) S: "DDMMYYYYHHmmss" TLS handshake -C: (6 bytes) + deflate(hash) +C: header + deflate(hash) header: 0x01 0xII 0xII 0xOO 0xOO 0x01, II é o tamanho da entrada, OO é o tamanho da saída do deflate hash: 0x40 + sequencia de chave/valor no formato byte 0: tamanho da chave | 0x80 se tamanho do valor maior que 255 (ou 127?) @@ -12,44 +12,65 @@ C: (6 bytes) + deflate(hash) ou byte[X] << 8 | byte[X+1] = tamanho do valor, se maior que 255 (ou 127?) valor com numero de bytes igual ao tamanho chaves: a_comp = 0x00 0x00 0x00 0x00 (4) - tp_arq = 0x00 0x00 0x08 0xfc (4) == 2300 em decimal, "Ajuste" (2321 - "Espolio", 2320 - "Saida") + tp_arq = 0x00 0x00 0x08 0xfc (4) == campo codigo_recnet em decimal id_dec = 0xXX 0xXX 0xXX 0xXX (4) == "hash" da declaracao com 10 digitos decimais exemplo: se "hash" == 1000000000, id_dec == 0x3b 0x9a 0xca 0x00 - exercicio = "2012" - exercico_pgd = "2013" + exercicio = campo exerc em ASCII + exercico_pgd = campo ano em ASCII hash_arq = 16 bytes - hash_trans = 16 bytes == hash_arq - ni = "00000000000" (CPF em ascii) + hash_trans = hash_arq + ni = campo cpf em ASCII, somente números tp_ni = "CPF" num_ass = 0x00 (assinatura e-CPF?) p_comp = 0x00 0x00 0x00 0x00 - ret = 0x00 + ret = campo in_ret em byte (0x00 ou 0x01) tam_arq = 8 bytes - tam_assinado = 8 bytes == tam_arq - tam_trans = 8 bytes == tam_arq - uf = "SP" (UF) + tam_assinado = tam_arq + tam_trans = tam_arq + uf = campo uf em ASCII vrs_des_pa = 0x00 (versão de desenvolvimento?) - versao_pgd = 0x00 0x78 (120, mesmo que nr_versao no DEC, segundo arquivo de leiaute) + versao_pgd = campo nr_versao critica_validador = 0x06 (??) - ip_loc = "127.0.0.1" (endereço IP local) - versao_java = "1.5.0-gij;Free Software rnetclient pretending to be GNU Interpreter for Java" (versão do Java em ASCII; o ReceitaNet concatena as propriedades java.version e java.runtime.name, com ";" entre elas) - origem = "JA2R" (melhor repetir!) - so = "GNU" - cliente = "201105" (identificador de versão do receitanet) - dados_val = parte do cabeçalho do DEC (desde in_cert até vr_totpagamentos) bytes RNET_HEADER_HEAD_yyyy a RNET_HEADER_SIZE_yyyy - RNET_HEADER_TAIL_yyyy + ip_loc = endereço IP da conexão, em ASCII com pontos + porta = porta da conexão + mac_address = campo mac, em ASCII, separado por traços + versao_java = campo jvm acrescido de ";OpenJDK Runtime Environment" (versão do Java em ASCII; o ReceitaNet concatena as propriedades java.version e java.runtime.name, com ";" entre elas) + origem = "JA2J" (melhor repetir!) + so = "Linux" + cliente = "201132" (identificador de versão do receitanet) + dados_val = parte do cabeçalho do DEC, bytes RNET_HEADER_HEAD_COMMON a RNET_HEADER_SIZE_yyyy - RNET_HEADER_TAIL_COMMON tam_dados_val = 0x00 0x00 0x00 0x00 (4 bytes) tam_dados_val_chave = 0x00 0x00 0x00 0x00 (4 bytes) arquivos_restantes = 0x00 0x00 0x00 0x00 (4 bytes) -S: (6 bytes) + deflate(hash) + +Até 2025, para autorizar o cliente a enviar o DEC: + S: header + deflate(hash) + header: 0x01 0xII 0xII 0xOO 0xOO 0x01, II é o tamanho da entrada, OO é o tamanho da saída do deflate + hash: 0xXX + sequencia de chave/valor no formato descrito acima (onde 0XX é um código) + 0x01 - Sucesso + pos_inicio = ?? + +A partir de 2026, para autorizar o cliente a enviar o DEC: + S: hash (sem header e nem deflate) + hash: 0xXX + sequencia de chave/valor no formato descrito acima (onde 0XX é um código) + 0x01 - Autorizado + pos_inicio = 0x00 8 vezes (??) + +Em todos os casos, depois da autorização: + C: header + deflate(conteúdo) + header: 0x01 0xII 0xII 0xOO 0xOO 0x00, II é o tamanho da entrada, OO é o tamanho da saída do deflate + conteúdo: arquivo DEC, com apenas os registros de declaração, ou seja, excluídos os registros de recibo, removido o número de controle (últimos 10 bytes) de todos os registros + O tamanho e o hash da mensagem anterior do cliente são o tamanho e o hash MD5 do conteúdo desta transmissão + +S: header + deflate(hash) header: 0x01 0xII 0xII 0xOO 0xOO 0x01, II é o tamanho da entrada, OO é o tamanho da saída do deflate hash: 0xXX + sequencia de chave/valor no formato descrito acima (onde 0XX é um código) - 0x01 - Sucesso - chave POS_INICIO - ?? - 0x03 - Erro - chave SUBTIPO - chave TEXTO: "XXXX.Erro xxxxxxxx", onde XXXX é o código de erro - chaves *ARQ* -C: (6 bytes) + deflate(hash) - header: 0x01 0xII 0xII 0xOO 0xOO 0x00, II é o tamanho da entrada, OO é o tamanho da saída do deflate - conteúdo: arquivo DEC, com apenas os registros de declaração, ou seja, excluídos os registros de recibo, removido o número de controle (últimos 10 bytes) de todos os registros - O tamanho e o hash da mensagem anterior do cliente são o tamanho e o hash MD5 do conteúdo desta transmissão + 0x03 - Erro, com as seguintes chaves: + subtipo + texto = "XXXX.Erro xxxxxxxx", onde XXXX é o código de erro + 0x04 - DEC recebido, com as seguintes chaves: + tipo_rec = + 0x00 = DEC aceito ou é novo + 0x01 = DEC negado ou já recebido + texto = Mensagem de sucesso ou de DEC já recebido + arquivo = arquivo REC em caso de aceite \ No newline at end of file diff --git a/rnet_encode.c b/rnet_encode.c index 1e2c66e..4a6e522 100644 --- a/rnet_encode.c +++ b/rnet_encode.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2013-2017 Thadeu Lima de Souza Cascardo - * Copyright (C) 2014 Alexandre Oliva + * Copyright (C) 2014, 2026 Alexandre Oliva + * Copyright (C) 2026 Adonay Felipe Nogueira (http://libreplanet.org/wiki/User:Adfeno) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -173,6 +174,7 @@ int rnet_encode(struct rnet_decfile *decfile, struct rnet_message **msg, struct r = rnet_message_add_u32(msg, "porta", connection_port); r = rnet_message_add_ascii(msg, "mac_address", connection_mac); r = rnet_message_add_ascii(msg, "versao_java", jvm); + // By lxoliva: Use same "origem" and "so" as reference. r = rnet_message_add_ascii(msg, "origem", "JA2J"); r = rnet_message_add_ascii(msg, "so", "Linux"); r = rnet_message_add_ascii(msg, "cliente", client); diff --git a/rnet_encode.h b/rnet_encode.h index 17f1f08..cd74ec9 100644 --- a/rnet_encode.h +++ b/rnet_encode.h @@ -1,5 +1,7 @@ /* * Copyright (C) 2013 Thadeu Lima de Souza Cascardo + * Copyright (C) 2026 Alexandre Oliva + * Copyright (C) 2026 Adonay Felipe Nogueira (http://libreplanet.org/wiki/User:Adfeno) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,6 +26,7 @@ #include "rnet_message.h" #include "decfile.h" +// By lxoliva: Use same client version as reference. #define RNET_DEFAULT_VERSION "201132" int rnet_cat(char **destination, const char *source); diff --git a/rnet_message.c b/rnet_message.c index a7ad17c..ef38e79 100644 --- a/rnet_message.c +++ b/rnet_message.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2013 Thadeu Lima de Souza Cascardo - * Copyright (C) 2014 Alexandre Oliva + * Copyright (C) 2014, 2026 Alexandre Oliva * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -74,6 +74,7 @@ static int add_field(struct rnet_message **message, char *key, int klen, { for (int i = 0; i < klen; i++) putchar (key[i]); + // By lxoliva: print chars as integers for easy debugging. printf ("%s", ": ("); for (int i = 0; i < vlen; i++) printf ("%i,", (int)val[i]); diff --git a/rnetclient.c b/rnetclient.c index fcdaafa..260af97 100644 --- a/rnetclient.c +++ b/rnetclient.c @@ -2,6 +2,7 @@ * Copyright (C) 2012-2014 Thadeu Lima de Souza Cascardo * Copyright (C) 2014 Alexandre Oliva * Copyright (C) 2014 Sergio Durigan Junior + * Copyright (C) 2026 Adonay Felipe Nogueira (http://libreplanet.org/wiki/User:Adfeno) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -346,41 +347,45 @@ static int rnet_send(gnutls_session_t session, char *buffer, size_t len, int hea return r; } +ssize_t rnet_try_recv(gnutls_session_t session, void *buffer, size_t bytes_requested) { + size_t bytes_read_total; + ssize_t bytes_read_now; + + bytes_read_total = 0; + while (bytes_read_total < bytes_requested) { + bytes_read_now = gnutls_record_recv(session, buffer + bytes_read_total, bytes_requested - bytes_read_total); + + if (bytes_read_now == 0) { + break; + } else if (bytes_read_now < 0) { + if (bytes_read_now == GNUTLS_E_INTERRUPTED || bytes_read_now == GNUTLS_E_AGAIN) { + sleep(1); + continue; + } + fprintf(stderr, "Error receiving response: %s\n", gnutls_strerror(bytes_read_now)); + return bytes_read_now; + } + bytes_read_total += bytes_read_now; + } + return bytes_read_total; +} + static int rnet_recv(gnutls_session_t session, struct rnet_message **message, int exerc) { char *out = NULL; size_t olen = 0; char *buffer; size_t len; + rnet_message_expand(message, 6); buffer = (*message)->buffer; - gnutls_record_recv(session, buffer, 6); - if (exerc >= 2026) { - /* FIXME: The server response may have changed: - - * 5th packet, C (unchanged): summary - of connection data and of DEC file, - but not DEC itself. - - * 6th packet, S (maybe different from - doc/FORMATO): (4 bytes) + 0x01 0x0a - pos_inicio 0x00 (9 times) - - * 7th packet: - * If file already sent, S - (idem): 0x04 0x08 tipo_rec... - - * If not sent, C (still - needs review): client sends - DEC file. - */ - fprintf(stderr, "Sending for the fiscal year %d may give errors, but proceeding anyway.\n", exerc); - } + rnet_try_recv(session, buffer, 6); + if (buffer[0] == 0x01) { len = chars2len((unsigned char *) buffer+1); rnet_message_expand(message, len); buffer = (*message)->buffer + 6; - gnutls_record_recv(session, buffer, len); + rnet_try_recv(session, buffer, len); inflateRecord(buffer - 6, len + 6, &out, &olen); rnet_message_del(*message); *message = NULL; @@ -390,9 +395,23 @@ static int rnet_recv(gnutls_session_t session, struct rnet_message **message, in free(out); } else { len = chars2len((unsigned char *) buffer+1); + if (exerc >= 2026 && len == 21) { + /* The server response that allows to go + ahead/send the DEC file has "0x01 0x01 0x0a + pos_inicio 0x08 0x00{8}" prefixed with + 0x15, which makes chars2len return 21. + However, after 0x0a, there are only 19 + characters left. Since the next functions + jump and reserve a position after 0x0a, we + set len to 20, otherwise, + gnutls_record_recv, which is used by + rnet_try_recv, would have blocked/frozen if + it was told to get 20 bytes (len - 1). */ + len -= 1; + } rnet_message_expand(message, len - 1); buffer = (*message)->buffer + 6; - gnutls_record_recv(session, buffer, len - 1); + rnet_try_recv(session, buffer, len - 1); (*message)->len = len + 4; rnet_message_strip(*message, 4); } @@ -459,6 +478,17 @@ static int save_rec_file(int fd, char *buffer, int len, const struct rnetclient_ return r; } +static int handle_response_go_ahead(struct rnet_message *message) +{ + char *value; + int vlen; + if (!rnet_message_parse(message, "pos_inicio", &value, &vlen)) { + return 0; + } + fprintf(stderr, "Error when looking for 'pos_inicio' in server response\n"); + return 1; +} + static void handle_response_text_and_file(int fd, struct rnet_message *message, const struct rnetclient_args *args) { char *value; @@ -590,7 +620,14 @@ int main(int argc, char **argv) } switch (message->buffer[0]) { case 1: /* go ahead */ - handle_response_text_and_file(outfd, message, &rnet_args); + if (exerc >= 2026) { + r = handle_response_go_ahead(message); + if (r) { + goto out; + } + } else { + handle_response_text_and_file(outfd, message, &rnet_args); + } break; case 3: /* error */ handle_response_error(message); diff --git a/t-parse.c b/t-parse.c index b61ce7f..d645c6d 100644 --- a/t-parse.c +++ b/t-parse.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2016 Gabriel F. T. Gomes + * Copyright (C) 2026 Adonay Felipe Nogueira (http://libreplanet.org/wiki/User:Adfeno) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by -- 2.34.1