[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