1 #define MODULE_LOG_PREFIX "radegast"
5 #include "oscam-client.h"
8 #include "oscam-string.h"
9 #include "oscam-reader.h"
10 #ifdef MODULE_STREAMRELAY
11 #include "module-streamrelay.h"
12 #include "oscam-chk.h"
15 static int32_t radegast_connect(void);
17 static int32_t radegast_send(struct s_client
*client
, uint8_t *buf
)
19 int32_t l
= buf
[1] + 2;
20 return (send(client
->pfd
, buf
, l
, 0));
23 static int32_t radegast_recv(struct s_client
*client
, uint8_t *buf
, int32_t l
)
26 if(!client
->pfd
) { return (-1); }
27 if(client
->typ
== 'c') // server code
29 if((n
= cs_recv(client
->pfd
, buf
, l
, 0)) > 0)
30 { client
->last
= time((time_t *) 0); }
34 if((n
= cs_recv(client
->pfd
, buf
, l
, 0)) > 0)
36 cs_log_dump_dbg(D_CLIENT
, buf
, n
, "radegast: received %d bytes from %s", n
, remote_txt());
37 client
->last
= time((time_t *) 0);
38 if((buf
[0] == 0x02) && (buf
[1] == 0x12) && (buf
[2] == 0x05) && (buf
[3] == 0x10)) { return (n
); } // dcw received
39 else if((buf
[0] == 0x02) && (buf
[1] == 0x02) && (buf
[2] == 0x04) && (buf
[3] == 0x00)) { return (n
); } // dcw no found
40 else if((buf
[0] == 0x81) && (buf
[1] == 0x00)) { return (n
); } // cmd unknown
41 else { n
= -1; }// no cmd radegast disconnect
47 static int32_t radegast_recv_chk(struct s_client
*client
, uint8_t *dcw
, int32_t *rc
, uint8_t *buf
, int32_t UNUSED(n
))
49 if((buf
[0] == 2) && (buf
[1] == 0x12))
52 memcpy(dcw
, buf
+ 4, 16);
53 cs_log_dbg(D_CLIENT
, "radegast: recv chk - %s", cs_hexdump(0, dcw
, 16, tmp_dbg
, sizeof(tmp_dbg
)));
55 return (client
->reader
->msg_idx
);
61 static void radegast_auth_client(IN_ADDR_T ip
)
64 struct s_auth
*account
;
65 struct s_client
*cl
= cur_client();
67 ok
= check_ip(cfg
.rad_allowed
, ip
);
71 cs_log("radegast: IP not allowed");
72 cs_auth_client(cl
, (struct s_auth
*)0, NULL
);
73 cs_disconnect_client(cl
);
76 for(ok
= 0, account
= cfg
.account
; cfg
.rad_usr
&& account
&& !ok
; account
= account
->next
)
78 ok
= streq(cfg
.rad_usr
, account
->usr
);
79 if(ok
&& cs_auth_client(cl
, account
, NULL
))
80 { cs_disconnect_client(cl
); }
84 { cs_auth_client(cl
, ok
? account
: (struct s_auth
*)(-1), "radegast"); }
87 static void radegast_send_dcw(struct s_client
*client
, ECM_REQUEST
*er
)
90 mbuf
[0] = 0x02; // DCW
91 if(er
->rc
< E_NOTFOUND
)
93 #ifdef MODULE_STREAMRELAY
94 if(chk_ctab_ex(er
->caid
, &cfg
.stream_relay_ctab
) && cfg
.stream_relay_enabled
)
99 mbuf
[1] = 0x12; // len (overall)
100 mbuf
[2] = 0x05; // ACCESS
101 mbuf
[3] = 0x10; // len
102 memcpy(mbuf
+ 4, er
->cw
, 16);
106 mbuf
[1] = 0x02; // len (overall)
107 mbuf
[2] = 0x04; // NO ACCESS
108 mbuf
[3] = 0x00; // len
110 radegast_send(client
, mbuf
);
113 static void radegast_process_ecm(uint8_t *buf
, int32_t l
)
117 struct s_client
*cl
= cur_client();
119 if(!(er
= get_ecmtask()))
122 for(i
= 0; i
+1 < l
; i
+= (sl
+ 2))
128 case 2: // CAID (upper byte only, oldstyle)
131 er
->caid
= buf
[i
+ 2] << 8;
137 er
->caid
= b2i(2, buf
+ i
+ 2);
143 er
->ecmlen
= (((buf
[i
+ 1 + 2] & 0x0F) << 8) | buf
[i
+ 2 + 2]) + 3;
144 if(er
->ecmlen
< 3 || er
->ecmlen
> MAX_ECM_SIZE
|| i
+2+er
->ecmlen
> l
)
146 memcpy(er
->ecm
, buf
+ i
+ 2, er
->ecmlen
);
149 case 6: // PROVID (ASCII)
152 n
= (sl
> 6) ? 3 : (sl
>> 1);
153 er
->prid
= cs_atoi((char *) buf
+ i
+ 2 + sl
- (n
<< 1), n
, 0);
156 case 7: // KEYNR (ASCII), not needed
159 case 8: // ECM PROCESS PID ?? don't know, not needed
162 case 9: // Adding srvid because ECM contains 0000
165 er
->srvid
= (buf
[i
+ 4] << 8 ) | (buf
[i
+ 2]);
171 { cs_log("WARNING: ECM-request corrupt"); }
176 static void radegast_process_unknown(uint8_t *buf
)
178 uint8_t answer
[2] = {0x81, 0x00};
179 radegast_send(cur_client(), answer
);
180 cs_log("unknown request %02X, len=%d", buf
[0], buf
[1]);
183 static void *radegast_server(struct s_client
*client
, uint8_t *mbuf
, int32_t n
)
188 if(!client
->init_done
)
190 radegast_auth_client(cur_client()->ip
);
191 client
->init_done
= 1;
197 radegast_process_ecm(mbuf
+ 2, mbuf
[1]);
201 radegast_process_unknown(mbuf
);
207 static int32_t radegast_send_ecm(struct s_client
*client
, ECM_REQUEST
*er
)
209 uint8_t provid_buf
[8];
210 uint8_t header
[22] = "\x02\x01\x00\x06\x08\x30\x30\x30\x30\x30\x30\x30\x30\x07\x04\x30\x30\x30\x38\x08\x01\x02";
214 uint8_t *via_ecm_mod
;
215 uint32_t n
, k
, Len
, pos
= 0;
217 if(!radegast_connect())
220 if(!cs_malloc(&ecmbuf
, er
->ecmlen
+ 30))
223 // Quickfix to suppress SubECMs with CWsSwap set to 01
224 // Applied only on Viaccess (CAID: 0x0500)
225 // this reduce the size of the ECM from long to short
226 // 40 07 03 0B 00 08 07 01 00 ... -> to keep
227 // 40 07 03 0B 00 08 07 01 01 ... -> to delete
228 // Thanks to luffy for the tip and the code.
230 if(er
->caid
== 0x500)
232 cs_log_dump_dbg(D_ATR
, er
->ecm
, er
->ecmlen
, "%s: ecm dump BEFORE suppressing SubECMs with CWsSwap set to 01", __func__
);
234 if(cs_malloc (&via_ecm_mod
, Len
+4))
236 if(er
->ecm
[4] == 0x80)
238 memcpy(via_ecm_mod
, er
->ecm
, 4);
239 via_ecm_mod
[1] = 0x70;
240 via_ecm_mod
[2] = 0x01;
245 SubECMp
= (uint8_t *)&er
->ecm
[k
];
246 if(((pos
+ SubECMp
[1] + 2) > 0xE0) || (pos
+ SubECMp
[1] + 2) > Len
)
251 if (SubECMp
[2] == 0xD2)
253 if(SubECMp
[0x0E] == 0x00)
255 memcpy(via_ecm_mod
+pos
, SubECMp
, SubECMp
[1] + 2);
256 via_ecm_mod
[2] += SubECMp
[1] + 2;
257 pos
+= SubECMp
[1] + 2;
260 else if ((SubECMp
[2] == 0x90 || SubECMp
[2] == 0x40) && SubECMp
[3] == 0x07)
262 if(SubECMp
[0x0A] == 0x00 || SubECMp
[0x0A] == 0xFF)
264 memcpy(via_ecm_mod
+ pos
, SubECMp
, SubECMp
[1] + 2);
265 via_ecm_mod
[2] += SubECMp
[1] + 2;
266 pos
+= SubECMp
[1] + 2;
271 Len
= via_ecm_mod
[2] + 3;
273 memcpy(er
->ecm
, via_ecm_mod
, Len
);
274 cs_log_dump_dbg(D_ATR
, er
->ecm
, er
->ecmlen
, "%s: ecm dump AFTER suppressing SubECMs with CWsSwap set to 01", __func__
);
276 NULLFREE(via_ecm_mod
);
282 ecmbuf
[1] = (er
->ecmlen
+ 30 - 2) & 0xff;
283 memcpy(ecmbuf
+ 2, header
, sizeof(header
));
284 for(n
= 0; n
< 4; n
++)
286 snprintf((char *)provid_buf
+ (n
* 2), sizeof(provid_buf
) - (n
* 2), "%02X", ((uint8_t *)(&er
->prid
))[4 - 1 - n
]);
288 ecmbuf
[7] = provid_buf
[0];
289 ecmbuf
[8] = provid_buf
[1];
290 ecmbuf
[9] = provid_buf
[2];
291 ecmbuf
[10] = provid_buf
[3];
292 ecmbuf
[11] = provid_buf
[4];
293 ecmbuf
[12] = provid_buf
[5];
294 ecmbuf
[13] = provid_buf
[6];
295 ecmbuf
[14] = provid_buf
[7];
296 ecmbuf
[2 + sizeof(header
)] = 0xa;
297 ecmbuf
[3 + sizeof(header
)] = 2;
298 ecmbuf
[4 + sizeof(header
)] = er
->caid
>> 8;
299 ecmbuf
[5 + sizeof(header
)] = er
->caid
& 0xff;
300 ecmbuf
[6 + sizeof(header
)] = 3;
301 ecmbuf
[7 + sizeof(header
)] = er
->ecmlen
& 0xff;
302 memcpy(ecmbuf
+ 8 + sizeof(header
), er
->ecm
, er
->ecmlen
);
303 ecmbuf
[4] = er
->caid
>> 8;
305 client
->reader
->msg_idx
= er
->idx
;
306 n
= send(client
->pfd
, ecmbuf
, er
->ecmlen
+ 30, 0);
308 cs_log_dbg(D_TRACE
, "radegast: sending ecm");
309 cs_log_dump_dbg(D_CLIENT
, ecmbuf
, er
->ecmlen
+ 30, "ecm:");
311 return ((n
< 1) ? (-1) : 0);
314 int32_t radegast_cli_init(struct s_client
*cl
)
318 handle
= network_tcp_connection_open(cl
->reader
);
319 if(handle
< 0) { return -1; }
321 cs_log("radegast: proxy %s:%d (fd=%d)", cl
->reader
->device
, cl
->reader
->r_port
, cl
->udp_fd
);
323 cl
->reader
->tcp_connected
= 2;
324 cl
->reader
->card_status
= CARD_INSERTED
;
325 cl
->reader
->last_g
= cl
->reader
->last_s
= time((time_t *)0);
327 cs_log_dbg(D_CLIENT
, "radegast: last_s=%ld, last_g=%ld", cl
->reader
->last_s
, cl
->reader
->last_g
);
329 cl
->pfd
= cl
->udp_fd
;
334 static void radegast_server_init(struct s_client
*cl
)
339 { cs_log("radegast: new connection from %s", cs_inet_ntoa(cl
->ip
)); }
340 radegast_auth_client(cur_client()->ip
);
346 static int32_t radegast_connect(void)
348 struct s_client
*cl
= cur_client();
350 if(cl
->reader
->tcp_connected
< 2 && radegast_cli_init(cl
) < 0)
359 void radegast_idle(void)
361 struct s_client
*client
= cur_client();
362 struct s_reader
*rdr
= client
->reader
;
363 time_t now
= time(NULL
);
369 time_diff
= llabs(now
- rdr
->last_s
);
370 if(time_diff
> (rdr
->tcp_ito
))
372 network_tcp_connection_close(rdr
, "inactivity");
376 else if(rdr
->tcp_ito
== -1)
383 void module_radegast(struct s_module
*ph
)
386 ph
->ptab
.ports
[0].s_port
= cfg
.rad_port
;
388 ph
->desc
= "radegast";
389 ph
->type
= MOD_CONN_TCP
;
390 ph
->large_ecm_support
= 1;
391 ph
->listenertype
= LIS_RADEGAST
;
392 IP_ASSIGN(ph
->s_ip
, cfg
.rad_srvip
);
393 ph
->s_handler
= radegast_server
;
394 ph
->s_init
= radegast_server_init
;
395 ph
->c_idle
= radegast_idle
;
396 ph
->recv
= radegast_recv
;
397 ph
->send_dcw
= radegast_send_dcw
;
398 ph
->c_init
= radegast_cli_init
;
399 ph
->c_recv_chk
= radegast_recv_chk
;
400 ph
->c_send_ecm
= radegast_send_ecm
;
401 ph
->num
= R_RADEGAST
;