void add_link_layer_address(unsigned char *ip, unsigned char *link_layer) { uint8_t i, min_time_idx = 0; uint32_t min_time; min_time = _link_layer_table[0].timestamp; for (i = 0 ; i < LINK_LAYER_CACHE_MAX_ENTRY ; ++i) { if (_link_layer_table[i].timestamp < min_time) { min_time = _link_layer_table[i].timestamp; min_time_idx = i; } if (IP_EQUAL(_link_layer_table[i].ip,ip) || IP_IS_NULL(_link_layer_table[i].ip)) { memcpy(_link_layer_table[i].link_layer, link_layer, LINK_LAYER_ADDRESS_SIZE); _link_layer_table[i].timestamp = NOW; if (IP_IS_NULL(_link_layer_table[i].ip)) { COPY_IP(_link_layer_table[i].ip,ip); } return; } } /* every entry is used, remove the oldest one */ COPY_IP(_link_layer_table[min_time_idx].ip,ip); memcpy(_link_layer_table[min_time_idx].link_layer, link_layer, LINK_LAYER_ADDRESS_SIZE); }
/* * Creates a string ready to write as a token into config or WebIf for an iprange. You must free the returned value through free_mk_t(). */ char *mk_t_iprange(struct s_ip *range) { struct s_ip *cip; char *value, *dot = ""; int32_t needed = 1, pos = 0; for(cip = range; cip; cip = cip->next) { needed += 32; } char tmp[needed]; for(cip = range; cip; cip = cip->next) { pos += snprintf(tmp + pos, needed - pos, "%s%s", dot, cs_inet_ntoa(cip->ip[0])); if(!IP_EQUAL(cip->ip[0], cip->ip[1])) { pos += snprintf(tmp + pos, needed - pos, "-%s", cs_inet_ntoa(cip->ip[1])); } dot = ","; } if(pos == 0 || !cs_malloc(&value, pos + 1)) { return ""; } memcpy(value, tmp, pos + 1); return value; }
/* Resolves the ip of the hostname of the specified account and saves it in account->dynip. If the hostname is not configured, the ip is set to 0. */ static void cs_user_resolve(struct s_auth *account) { if (account->dyndns) { IN_ADDR_T lastip; IP_ASSIGN(lastip, account->dynip); cs_resolve(account->dyndns, &account->dynip, NULL, NULL); if (!IP_EQUAL(lastip, account->dynip)) { cs_log("%s: resolved ip=%s", account->dyndns, cs_inet_ntoa(account->dynip)); } } else { set_null_ip(&account->dynip); } }
int get_link_layer_address(const unsigned char *ip, unsigned char *link_layer) { uint8_t i; for (i = 0 ; i < LINK_LAYER_CACHE_MAX_ENTRY ; ++i) { if (IP_EQUAL(_link_layer_table[i].ip,ip)) { memcpy(link_layer, _link_layer_table[i].link_layer, LINK_LAYER_ADDRESS_SIZE); return 1; } } return 0; }
// if input client is typ proxy get client and vice versa struct s_client *switch_client_proxy(struct s_client *cli) { struct s_client *cl; int8_t typ; if(cli->typ == 'c') { typ = 'p'; } else { typ = 'c'; } for(cl = first_client; cl; cl = cl->next) { //needfix: only one gbox per IP. Ports? if(IP_EQUAL(cli->ip, cl->ip) && cl->typ == typ && cl->gbox) { return cl; } } return cli; }
xkern_return_t rt_init( XObj self, IPhost *defGw ) { PState *ps = (PState *)self->state; RouteTable *tbl = &ps->rtTbl; Path path = self->path; Event ev; xTrace0(ipp, TR_GROSS_EVENTS, "IP rt_init()"); tbl->valid = TRUE; tbl->defrt = 0; tbl->arr = (route **)pathAlloc(path, ROUTETABLESIZE * sizeof(route *)); tbl->path = path; if ( ! tbl->arr ) { xTraceP0(self, TR_ERRORS, "allocation failure"); return XK_FAILURE; } bzero((char *)tbl->arr, ROUTETABLESIZE * sizeof(route *)); tbl->bpoolsize = BPSIZE; if ( ! (ev = evAlloc(path)) ) { pathFree(tbl->arr); xTraceP0(self, TR_ERRORS, "allocation failure"); return XK_FAILURE; } if ( IP_EQUAL(*defGw, ipNull) ) { xTrace0(ipp, TR_GROSS_EVENTS, "IP routing -- default routing disabled"); } else { if ( rt_add_def(ps, defGw) ) { return XK_FAILURE; } } evSchedule(ev, rt_timer, tbl, RTTABLEUPDATE * 1000); xTrace0(ipp, TR_GROSS_EVENTS, "IP rt_init() done"); return XK_SUCCESS; }
/** * cacheex modes: * * cacheex=1 CACHE PULL: * Situation: oscam A reader1 has cacheex=1, oscam B account1 has cacheex=1 * oscam A gets a ECM request, reader1 send this request to oscam B, oscam B checks his cache * a. not found in cache: return NOK * a. found in cache: return OK+CW * b. not found in cache, but found pending request: wait max cacheexwaittime and check again * oscam B never requests new ECMs * * CW-flow: B->A * * cacheex=2 CACHE PUSH: * Situation: oscam A reader1 has cacheex=2, oscam B account1 has cacheex=2 * if oscam B gets a CW, its pushed to oscam A * reader has normal functionality and can request ECMs * * Problem: oscam B can only push if oscam A is connected * Problem or feature?: oscam A reader can request ecms from oscam B * * CW-flow: B->A * */ void cacheex_cache_push(ECM_REQUEST *er) { if(er->rc >= E_NOTFOUND) { return; } //cacheex=2 mode: push (server->remote) struct s_client *cl; cs_readlock(&clientlist_lock); for(cl = first_client->next; cl; cl = cl->next) { if(check_client(cl) && er->cacheex_src != cl) { if(get_module(cl)->num == R_CSP) // always send to csp cl { if(!er->cacheex_src || cfg.csp.allow_reforward) { cacheex_cache_push_to_client(cl, er); // but not if the origin was cacheex (might loop) } } else if(cl->typ == 'c' && !cl->dup && cl->account && cl->account->cacheex.mode == 2) //send cache over user { if(get_module(cl)->c_cache_push // cache-push able && (!er->grp || (cl->grp & er->grp)) //Group-check /**** OUTGOING FILTER CHECK ***/ && (!er->selected_reader || !cacheex_reader(er->selected_reader) || !cfg.block_same_name || strcmp(username(cl), er->selected_reader->label)) //check reader mode-1 loopback by same name && (!er->selected_reader || !cacheex_reader(er->selected_reader) || !cfg.block_same_ip || (check_client(er->selected_reader->client) && !IP_EQUAL(cl->ip, er->selected_reader->client->ip))) //check reader mode-1 loopback by same ip && (!cl->account->cacheex.drop_csp || checkECMD5(er)) //cacheex_drop_csp-check && chk_ctab(er->caid, &cl->ctab) //Caid-check && (!checkECMD5(er) || chk_ident_filter(er->caid, er->prid, &cl->ftab)) //Ident-check (not for csp: prid=0 always!) && chk_srvid(cl, er) //Service-check ) { cacheex_cache_push_to_client(cl, er); } } } } cs_readunlock(&clientlist_lock); //cacheex=3 mode: reverse push (reader->server) cs_readlock(&readerlist_lock); cs_readlock(&clientlist_lock); struct s_reader *rdr; for(rdr = first_active_reader; rdr; rdr = rdr->next) { cl = rdr->client; if(check_client(cl) && er->cacheex_src != cl && rdr->cacheex.mode == 3) //send cache over reader { if(rdr->ph.c_cache_push // cache-push able && (!er->grp || (rdr->grp & er->grp)) //Group-check /**** OUTGOING FILTER CHECK ***/ && (!er->selected_reader || !cacheex_reader(er->selected_reader) || !cfg.block_same_name || strcmp(username(cl), er->selected_reader->label)) //check reader mode-1 loopback by same name && (!er->selected_reader || !cacheex_reader(er->selected_reader) || !cfg.block_same_ip || (check_client(er->selected_reader->client) && !IP_EQUAL(cl->ip, er->selected_reader->client->ip))) //check reader mode-1 loopback by same ip && (!rdr->cacheex.drop_csp || checkECMD5(er)) //cacheex_drop_csp-check && chk_ctab(er->caid, &rdr->ctab) //Caid-check && (!checkECMD5(er) || chk_ident_filter(er->caid, er->prid, &rdr->ftab)) //Ident-check (not for csp: prid=0 always!) && chk_srvid(cl, er) //Service-check ) { cacheex_cache_push_to_client(cl, er); } } } cs_readunlock(&clientlist_lock); cs_readunlock(&readerlist_lock); }
int32_t cs_auth_client(struct s_client * client, struct s_auth *account, const char *e_txt) { int32_t rc = 0; unsigned char md5tmp[MD5_DIGEST_LENGTH]; char buf[32]; char *t_crypt = "encrypted"; char *t_plain = "plain"; char *t_grant = " granted"; char *t_reject = " rejected"; char *t_msg[] = { buf, "invalid access", "invalid ip", "unknown reason", "protocol not allowed" }; struct s_module *module = get_module(client); memset(&client->grp, 0xff, sizeof(uint64_t)); //client->grp=0xffffffffffffff; if ((intptr_t)account != 0 && (intptr_t)account != -1 && account->disabled) { cs_add_violation(client, account->usr); cs_log("%s %s-client %s%s (%s%sdisabled account)", client->crypted ? t_crypt : t_plain, module->desc, IP_ISSET(client->ip) ? cs_inet_ntoa(client->ip) : "", IP_ISSET(client->ip) ? t_reject : t_reject+1, e_txt ? e_txt : "", e_txt ? " " : ""); return 1; } // check whether client comes in over allowed protocol if ((intptr_t)account != 0 && (intptr_t)account != -1 && (intptr_t)account->allowedprotocols && (((intptr_t)account->allowedprotocols & module->listenertype) != module->listenertype)) { cs_add_violation(client, account->usr); cs_log("%s %s-client %s%s (%s%sprotocol not allowed)", client->crypted ? t_crypt : t_plain, module->desc, IP_ISSET(client->ip) ? cs_inet_ntoa(client->ip) : "", IP_ISSET(client->ip) ? t_reject : t_reject+1, e_txt ? e_txt : "", e_txt ? " " : ""); return 1; } client->account = first_client->account; switch((intptr_t)account) { case 0: { // reject access rc = 1; cs_add_violation(client, NULL); cs_log("%s %s-client %s%s (%s)", client->crypted ? t_crypt : t_plain, module->desc, IP_ISSET(client->ip) ? cs_inet_ntoa(client->ip) : "", IP_ISSET(client->ip) ? t_reject : t_reject+1, e_txt ? e_txt : t_msg[rc]); break; } default: { // grant/check access if (IP_ISSET(client->ip) && account->dyndns) { if (!IP_EQUAL(client->ip, account->dynip)) cs_user_resolve(account); if (!IP_EQUAL(client->ip, account->dynip)) { cs_add_violation(client, account->usr); rc=2; } } client->monlvl = account->monlvl; client->account = account; if (!rc) { client->dup=0; if (client->typ=='c' || client->typ=='m') client->pcrc = crc32(0L, MD5((uchar *)(ESTR(account->pwd)), strlen(ESTR(account->pwd)), md5tmp), MD5_DIGEST_LENGTH); if (client->typ=='c') { client->last_caid = NO_CAID_VALUE; client->last_srvid = NO_SRVID_VALUE; client->expirationdate = account->expirationdate; client->disabled = account->disabled; client->allowedtimeframe[0] = account->allowedtimeframe[0]; client->allowedtimeframe[1] = account->allowedtimeframe[1]; if (account->firstlogin == 0) account->firstlogin = time((time_t*)0); client->failban = account->failban; client->c35_suppresscmd08 = account->c35_suppresscmd08; client->ncd_keepalive = account->ncd_keepalive; client->grp = account->grp; client->aureader_list = account->aureader_list; client->autoau = account->autoau; client->tosleep = (60*account->tosleep); client->c35_sleepsend = account->c35_sleepsend; memcpy(&client->ctab, &account->ctab, sizeof(client->ctab)); if (account->uniq) cs_fake_client(client, account->usr, account->uniq, client->ip); client->ftab = account->ftab; // IDENT filter client->cltab = account->cltab; // CLASS filter client->fchid = account->fchid; // CHID filter client->sidtabs.ok= account->sidtabs.ok; // services client->sidtabs.no= account->sidtabs.no; // services memcpy(&client->ttab, &account->ttab, sizeof(client->ttab)); ac_init_client(client, account); } } } case -1: { // anonymous grant access if (rc) { t_grant = t_reject; } else { if (client->typ == 'm') { snprintf(t_msg[0], sizeof(buf), "lvl=%d", client->monlvl); } else { int32_t rcount = ll_count(client->aureader_list); snprintf(buf, sizeof(buf), "au="); if (!rcount) snprintf(buf+3, sizeof(buf)-3, "off"); else { if (client->autoau) snprintf(buf+3, sizeof(buf)-3, "auto (%d reader)", rcount); else snprintf(buf+3, sizeof(buf)-3, "on (%d reader)", rcount); } } } cs_log("%s %s-client %s%s (%s, %s)", client->crypted ? t_crypt : t_plain, e_txt ? e_txt : module->desc, IP_ISSET(client->ip) ? cs_inet_ntoa(client->ip) : "", IP_ISSET(client->ip) ? t_grant : t_grant + 1, username(client), t_msg[rc]); break; } } return rc; }
static void cs_fake_client(struct s_client *client, char *usr, int32_t uniq, IN_ADDR_T ip) { /* Uniq = 1: only one connection per user * * Uniq = 2: set (new connected) user only to fake if source * ip is different (e.g. for newcamd clients with * different CAID's -> Ports) * * Uniq = 3: only one connection per user, but only the last * login will survive (old mpcs behavior) * * Uniq = 4: set user only to fake if source ip is * different, but only the last login will survive */ struct s_client *cl; struct s_auth *account; cs_writelock(&fakeuser_lock); for (cl = first_client->next; cl; cl = cl->next) { account = cl->account; if (cl != client && cl->typ == 'c' && !cl->dup && account && streq(account->usr, usr) && uniq < 5 && ((uniq % 2) || !IP_EQUAL(cl->ip, ip))) { char buf[20]; if (uniq == 3 || uniq == 4) { cl->dup = 1; cl->aureader_list = NULL; cs_strncpy(buf, cs_inet_ntoa(cl->ip), sizeof(buf)); cs_log("client(%8lX) duplicate user '%s' from %s (prev %s) set to fake (uniq=%d)", (unsigned long)cl->thread, usr, cs_inet_ntoa(ip), buf, uniq); if (cl->failban & BAN_DUPLICATE) { cs_add_violation(cl, usr); } if (cfg.dropdups) { cs_writeunlock(&fakeuser_lock); cs_sleepms(100); // sleep a bit to prevent against saturation from fast reconnecting clients kill_thread(cl); cs_writelock(&fakeuser_lock); } } else { client->dup = 1; client->aureader_list = NULL; cs_strncpy(buf, cs_inet_ntoa(ip), sizeof(buf)); cs_log("client(%8lX) duplicate user '%s' from %s (current %s) set to fake (uniq=%d)", (unsigned long)pthread_self(), usr, cs_inet_ntoa(cl->ip), buf, uniq); if (client->failban & BAN_DUPLICATE) { cs_add_violation_by_ip(ip, get_module(client)->ptab->ports[client->port_idx].s_port, usr); } if (cfg.dropdups) { cs_writeunlock(&fakeuser_lock); // we need to unlock here as cs_disconnect_client kills the current thread! cs_sleepms(100); // sleep a bit to prevent against saturation from fast reconnecting clients cs_disconnect_client(client); cs_writelock(&fakeuser_lock); } break; } } } cs_writeunlock(&fakeuser_lock); }
static int32_t cs_check_v(IN_ADDR_T ip, int32_t port, int32_t add, char *info, int32_t acosc_penalty_duration) { int32_t result = 0; bool acosc_enabled = false; #ifdef CS_ANTICASC if(cfg.acosc_enabled) acosc_enabled = true; #endif if(!(cfg.failbantime || acosc_enabled)) { return 0; } if(!cfg.v_list) { cfg.v_list = ll_create("v_list"); } struct timeb (now); cs_ftime(&now); LL_ITER itr = ll_iter_create(cfg.v_list); V_BAN *v_ban_entry; int32_t ftime = cfg.failbantime * 60 * 1000; //run over all banned entries to do housekeeping: while((v_ban_entry = ll_iter_next(&itr))) { // housekeeping: int32_t gone = comp_timeb(&now, &v_ban_entry->v_time); if(((gone >= ftime) && !v_ban_entry->acosc_entry) || (v_ban_entry->acosc_entry && ((gone/1000) >= v_ban_entry->acosc_penalty_dur))) // entry out of time->remove { NULLFREE(v_ban_entry->info); ll_iter_remove_data(&itr); continue; } if(IP_EQUAL(ip, v_ban_entry->v_ip) && port == v_ban_entry->v_port) { result = 1; if(!info) { info = v_ban_entry->info; } else if(!v_ban_entry->info) { v_ban_entry->info = cs_strdup(info); } if(!add) { if(v_ban_entry->v_count >= cfg.failbancount) { if(!v_ban_entry->acosc_entry) { cs_debug_mask(D_TRACE, "failban: banned ip %s:%d - %d seconds left%s%s", cs_inet_ntoa(v_ban_entry->v_ip), v_ban_entry->v_port, (ftime - gone)/1000, info ? ", info: " : "", info ? info : ""); } else { cs_debug_mask(D_TRACE, "failban: banned ip %s:%d - %d seconds left%s%s", cs_inet_ntoa(v_ban_entry->v_ip), v_ban_entry->v_port, (v_ban_entry->acosc_penalty_dur - (gone/1000)), info?", info: ":"", info?info:""); } } else { cs_debug_mask(D_TRACE, "failban: ip %s:%d chance %d of %d%s%s", cs_inet_ntoa(v_ban_entry->v_ip), v_ban_entry->v_port, v_ban_entry->v_count, cfg.failbancount, info ? ", info: " : "", info ? info : ""); v_ban_entry->v_count++; } } else { cs_debug_mask(D_TRACE, "failban: banned ip %s:%d - already exist in list%s%s", cs_inet_ntoa(v_ban_entry->v_ip), v_ban_entry->v_port, info ? ", info: " : "", info ? info : ""); } } } if(add && !result) { if(cs_malloc(&v_ban_entry, sizeof(V_BAN))) { cs_ftime(&v_ban_entry->v_time); v_ban_entry->v_ip = ip; v_ban_entry->v_port = port; v_ban_entry->v_count = 1; v_ban_entry->acosc_entry = false; v_ban_entry->acosc_penalty_dur = 0; if(acosc_penalty_duration > 0) { v_ban_entry->v_count = cfg.failbancount +1; // set it to a higher level v_ban_entry->acosc_entry = true; v_ban_entry->acosc_penalty_dur = acosc_penalty_duration; } if(info) { v_ban_entry->info = cs_strdup(info); } ll_iter_insert(&itr, v_ban_entry); cs_debug_mask(D_TRACE, "failban: ban ip %s:%d with timestamp %ld%s%s", cs_inet_ntoa(v_ban_entry->v_ip), v_ban_entry->v_port, v_ban_entry->v_time.time, info ? ", info: " : "", info ? info : ""); } } return result; }