/* Apply RDP cookie persistence to the current session. For this, the function * tries to extract an RDP cookie from the request buffer, and look for the * matching server in the list. If the server is found, it is assigned to the * session. This always returns 1, and the analyser removes itself from the * list. Nothing is performed if a server was already assigned. */ int tcp_persist_rdp_cookie(struct session *s, struct channel *req, int an_bit) { struct proxy *px = s->be; int ret; struct sample smp; struct server *srv = px->srv; struct sockaddr_in addr; char *p; DPRINTF(stderr,"[%u] %s: session=%p b=%p, exp(r,w)=%u,%u bf=%08x bh=%d analysers=%02x\n", now_ms, __FUNCTION__, s, req, req->rex, req->wex, req->flags, req->buf->i, req->analysers); if (s->flags & SN_ASSIGNED) goto no_cookie; memset(&smp, 0, sizeof(smp)); ret = fetch_rdp_cookie_name(s, &smp, s->be->rdp_cookie_name, s->be->rdp_cookie_len); if (ret == 0 || (smp.flags & SMP_F_MAY_CHANGE) || smp.data.str.len == 0) goto no_cookie; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; /* Considering an rdp cookie detected using acl, str ended with <cr><lf> and should return */ addr.sin_addr.s_addr = strtoul(smp.data.str.str, &p, 10); if (*p != '.') goto no_cookie; p++; addr.sin_port = (unsigned short)strtoul(p, &p, 10); if (*p != '.') goto no_cookie; s->target = NULL; while (srv) { if (srv->addr.ss_family == AF_INET && memcmp(&addr, &(srv->addr), sizeof(addr)) == 0) { if ((srv->state != SRV_ST_STOPPED) || (px->options & PR_O_PERSIST)) { /* we found the server and it is usable */ s->flags |= SN_DIRECT | SN_ASSIGNED; s->target = &srv->obj_type; break; } } srv = srv->next; } no_cookie: req->analysers &= ~an_bit; req->analyse_exp = TICK_ETERNITY; return 1; }
/* RDP Cookie HASH. */ struct server *get_server_rch(struct session *s) { unsigned int hash = 0; struct proxy *px = s->be; unsigned long len; int ret; struct sample smp; int rewind; /* tot_weight appears to mean srv_count */ if (px->lbprm.tot_weight == 0) return NULL; memset(&smp, 0, sizeof(smp)); b_rew(s->req.buf, rewind = s->req.buf->o); ret = fetch_rdp_cookie_name(s, &smp, px->hh_name, px->hh_len); len = smp.data.str.len; b_adv(s->req.buf, rewind); if (ret == 0 || (smp.flags & SMP_F_MAY_CHANGE) || len == 0) return NULL; /* note: we won't hash if there's only one server left */ if (px->lbprm.tot_used == 1) goto hash_done; /* Found a the hh_name in the headers. * we will compute the hash based on this value ctx.val. */ hash = gen_hash(px, smp.data.str.str, len); if ((px->lbprm.algo & BE_LB_HASH_MOD) == BE_LB_HMOD_AVAL) hash = full_hash(hash); hash_done: if (px->lbprm.algo & BE_LB_LKUP_CHTREE) return chash_get_server_hash(px, hash); else return map_get_server_hash(px, hash); }
/* Fetch the request RDP cookie identified in the args, or any cookie if no arg * is passed. It is usable both for ACL and for samples. Note: this decoder * only works with non-wrapping data. Accepts either 0 or 1 argument. Argument * is a string (cookie name), other types will lead to undefined behaviour. */ int smp_fetch_rdp_cookie(struct proxy *px, struct session *s, void *l7, unsigned int opt, const struct arg *args, struct sample *smp, const char *kw) { return fetch_rdp_cookie_name(s, smp, args ? args->data.str.str : NULL, args ? args->data.str.len : 0); }