[IRPF-Livre, Rnetclient] Impossível enviar declaração
Alexandre Oliva
lxoliva en fsfla.org
Lun Mayo 25 09:33:00 UTC 2026
On May 24, 2026, Alexandre Oliva <lxoliva en fsfla.org> wrote:
> Outra descoberta talvez útil é que quem faz a validação do
> receitanet.jar a partir do sha1 em receitanet.dat é o próprio, em
> ControleReceitanet.a(). Em tese (porque não testei) bastaria explodir o
> .jar e usar o diretório em vez do .jar no classpath que ele deixa de
> verificar. Aí poderíamos substituir classes para experimentar, por
> exemplo, adicionar código para nos informar o que está acontecendo, o
> que está sendo enviado, o que está sendo recebido, enfim...
Consegui, explodindo o receitanet-pro-1.32.jar na raiz do IRPF2026,
rodar o aplicativo receitanet, inclusive com modificações.
java -cp lib/jsignnet-3.6.0.jar:lib/maven-artifact-3.8.4.jar:lib/bcprov-jdk18on-1.75.jar:lib/bcmail-jdk18on-1.75.jar:lib/bcpkix-jdk18on-1.75.jar:lib/bcutil-jdk18on-1.75.jar:lib/recnetutil-1.1.jar:lib/recnet-envelope-1.2.jar:. serpro.receitanet.gui.ReceitanetApp
Copiei os fontes descompilados pra serpro/receitanet e fiz alguns
ajustes para mostrar os dados adicionados à mensagem que subiria o
arquivo de declaração, e mais o suficiente para conseguir recompilar a
classe aa.java modificada com:
javac -cp lib/jsignnet-3.6.0.jar:lib/maven-artifact-3.8.4.jar:lib/bcprov-jdk18on-1.75.jar:lib/bcmail-jdk18on-1.75.jar:lib/bcpkix-jdk18on-1.75.jar:lib/bcutil-jdk18on-1.75.jar:lib/recnetutil-1.1.jar:lib/recnet-envelope-1.2.jar:. serpro/receitanet/aa.java
diff -druN '--exclude=recursos' '--exclude=*.class' serpro/receitanet.orig/aa.java serpro/receitanet/aa.java
--- serpro/receitanet.orig/aa.java 2026-04-14 05:52:05.135450506 -0300
+++ serpro/receitanet/aa.java 2026-05-25 05:29:45.925472660 -0300
@@ -28,6 +28,9 @@
return;
}
lowerCase = lowerCase.toLowerCase();
+ System.out.print(lowerCase + ": (");
+ for (int i = 0; i < array.length; i++) System.out.print ((int)array[i] + ",");
+ System.out.println(")");
if (array.length < 256) {
this.a.add((byte)Math.min(31, lowerCase.length()));
this.a.addAll(Conversoes.bytesFromString(lowerCase));
@@ -112,7 +115,7 @@
@Override
public final Map a(final byte[] array) {
- final HashMap<String, Boolean> hashMap = new HashMap<String, Boolean>();
+ final HashMap<String, Object> hashMap = new HashMap<String, Object>();
int n2;
int n3;
for (int i = 1; i < array.length; i = n2 + n3) {
@@ -131,24 +134,24 @@
n2 += 2;
}
final Integer n4;
- if ((n4 = this.d.get(upperCase)) != null) {
+ if ((n4 = (Integer)this.d.get(upperCase)) != null) {
final int intValue;
switch (intValue = n4) {
case 0: {
- hashMap.put(upperCase, (Boolean)Conversoes.stringFromBytes(array, n2, n3));
+ hashMap.put(upperCase, Conversoes.stringFromBytes(array, n2, n3));
break;
}
case 1: {
final byte[] value = new byte[n3];
System.arraycopy(array, n2, value, 0, n3);
- hashMap.put(upperCase, (Boolean)(Object)value);
+ hashMap.put(upperCase, value);
break;
}
case 2:
case 3:
case 4:
case 5: {
- hashMap.put(upperCase, (Boolean)(Object)new Long(Conversoes.longFromBytes(array, n2, n3)));
+ hashMap.put(upperCase, new Long(Conversoes.longFromBytes(array, n2, n3)));
break;
}
case 6: {
diff -druN '--exclude=recursos' '--exclude=*.class' serpro/receitanet.orig/t.java serpro/receitanet/t.java
--- serpro/receitanet.orig/t.java 2026-04-14 05:52:36.567418330 -0300
+++ serpro/receitanet/t.java 2026-05-25 05:14:41.400384016 -0300
@@ -26,16 +26,16 @@
}
public static String b(final String str) {
+ final Object o;
synchronized (t.d) {
- final Object o;
if (((Map)(o = t.d.get())).containsKey(str)) {
return ((Map<K, String>)o).get(str);
}
}
+ final Throwable t = (Throwable)o;
synchronized (t.c) {
- final Throwable t;
if (serpro.receitanet.t.c.containsKey(t)) {
- return serpro.receitanet.t.c.get(t);
+ return (String)serpro.receitanet.t.c.get(t);
}
}
try {
@@ -63,7 +63,7 @@
public static void b(final String s, final String s2) {
synchronized (t.d) {
- t.d.get().put(s, s2);
+ ((HashMap)t.d.get()).put(s, s2);
}
}
Daí restaurei os .class que não o aa e consegui retransmitir com sucesso
um arquivo de declaração já transmitido anteriormente através do próprio
IRPF2026. Uma tentativa de transmitir uma declaração virtualmente
idêntica, gerada pelo irpf-livre, com diferenças apenas na data/hora e
no endereço MAC, deu erro 5115 no Validador IRPF 2026; desconfio que
seja porque já houve declaração (com hash de recibo) diferente para o
mesmo CPF. Creio que dê pra concluir que desse jeito a transmissão
funciona, então podemos fazer mais experimentos.
Comparando a saída das transmissões com a saída do rnetclient, percebi
duas informações faltando no rnetclient: porta e mac_address (o endereço
com pares de dígitos hexadecimais maiúsculos separados por dois pontos).
Infelizmente, mesmo adicionando esses dados e ajustando outros campos
que preenchíamos com dados diferentes, inclusive IP e mac_address reais,
o rnetclient não conseguiu concluir a transmissão com sucesso, nem mesmo
da declaração transmitida previamente. O problema está provavelmente
noutra camada :-( Segue a investigação...
diff a/rnet_encode.c b/rnet_encode.c
--- a/rnet_encode.c
+++ b/rnet_encode.c
@@ -95,10 +95,12 @@ int rnet_encode(struct rnet_decfile *decfile, struct rnet_message **msg, char *c
r = rnet_message_add_u8(msg, "vrs_des_pa", 0);
r = rnet_message_add_u16(msg, "versao_pgd", versao_pgd);
r = rnet_message_add_u8(msg, "critica_validador", 0x06);
- r = rnet_message_add_ascii(msg, "ip_loc", "127.0.0.1");
- r = rnet_message_add_ascii(msg, "versao_java", "1.5.0-gij;Free Software rnetclient pretending to be GNU Interpreter for Java");
- r = rnet_message_add_ascii(msg, "origem", "JA2R");
- r = rnet_message_add_ascii(msg, "so", "GNU");
+ r = rnet_message_add_ascii(msg, "ip_loc", "127.0.0.2");
+ r = rnet_message_add_u32(msg, "porta", 50500);
+ r = rnet_message_add_ascii(msg, "mac_address", "AR:EC:EI:TA:FE:DE");
+ r = rnet_message_add_ascii(msg, "versao_java", "25.0.2;OpenJDK Runtime Environment");
+ r = rnet_message_add_ascii(msg, "origem", "JA2J");
+ r = rnet_message_add_ascii(msg, "so", "Linux");
r = rnet_message_add_ascii(msg, "cliente", client);
r = rnet_message_add_buffer(msg, "dados_val",
header + header_head,
diff --git a/rnet_encode.h b/rnet_encode.h
index 6ebbd9fae47cc..bd24f9be05782 100644
--- a/rnet_encode.h
+++ b/rnet_encode.h
@@ -22,7 +22,7 @@
#include "rnet_message.h"
#include "decfile.h"
-#define RNET_DEFAULT_VERSION "201704"
+#define RNET_DEFAULT_VERSION "201132"
int rnet_encode(struct rnet_decfile *decfile, struct rnet_message **msg, char *client);
diff --git a/rnet_message.c b/rnet_message.c
index 95d8b41fc225d..a7ad17ca005ac 100644
--- a/rnet_message.c
+++ b/rnet_message.c
@@ -23,6 +23,7 @@
#include <string.h>
#include <errno.h>
#include <netdb.h>
+#include <stdio.h>
#ifndef MAX
#define MAX(a,b) (a >= b) ? a : b
@@ -71,6 +72,12 @@ int rnet_message_strip(struct rnet_message *message, size_t len)
static int add_field(struct rnet_message **message, char *key, int klen,
char *val, int vlen)
{
+ for (int i = 0; i < klen; i++)
+ putchar (key[i]);
+ printf ("%s", ": (");
+ for (int i = 0; i < vlen; i++)
+ printf ("%i,", (int)val[i]);
+ printf ("%s", ")\n");
int n = 0;
char *buffer;
struct rnet_message *msg = *message;
--
Alexandre Oliva, happy hacker https://blog.lx.oliva.nom.br/
Free Software Activist FSFLA co-founder GNU Toolchain Engineer
Learn the truth about Richard Stallman at https://stallmansupport.org/
Más información sobre la lista de distribución Softwares-impostos