void del_ban(const char * addr) { netban_vector::iterator it; if(find_ban(addr, &it)) { netbans.erase(it); std::cout << "removed " << it->to_string() << " (hits: " << it->hits_value() << ") from network bans" << std::endl; } }
void add_ban(const char * addr, bool persist, const char * reason) { netban nb(addr, persist); if(nb.is_valid()) { if(find_ban(nb)) return; nb.set_reason(reason); netbans.push_back(nb); } }
void merge_pushed_bans() { if(stack.empty()) return; netban_vector oldbans = stack.front(); for(netban_vector::reverse_iterator it = oldbans.rbegin(); it != oldbans.rend(); ++it) { netban *newban = find_ban(*it); if(newban || it->persist_value()) { if(newban) *newban = *it; // update hits else netbans.push_back(*it); // re-add persist ban oldbans.erase(it.base()); } } for(netban_vector::iterator it = oldbans.begin(); it != oldbans.end(); ++it) { std::cout << "removed " << it->to_string() << " (hits: " << it->hits_value() << ") from network bans" << std::endl; } }
/** Handle a JOIN message from a client connection. * See @ref m_functions for discussion of the arguments. * @param[in] cptr Client that sent us the message. * @param[in] sptr Original source of message. * @param[in] parc Number of arguments. * @param[in] parv Argument vector. */ int m_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) { struct Channel *chptr; struct JoinBuf join; struct JoinBuf create; struct Gline *gline; char *p = 0; char *chanlist; char *name; char *keys; if (parc < 2 || *parv[1] == '\0') return need_more_params(sptr, "JOIN"); joinbuf_init(&join, sptr, cptr, JOINBUF_TYPE_JOIN, 0, 0); joinbuf_init(&create, sptr, cptr, JOINBUF_TYPE_CREATE, 0, TStime()); chanlist = last0(cptr, sptr, parv[1]); /* find last "JOIN 0" */ keys = parv[2]; /* remember where keys are */ for (name = ircd_strtok(&p, chanlist, ","); name; name = ircd_strtok(&p, 0, ",")) { char *key = 0; /* If we have any more keys, take the first for this channel. */ if (!BadPtr(keys) && (keys = strchr(key = keys, ','))) *keys++ = '\0'; /* Empty keys are the same as no keys. */ if (key && !key[0]) key = 0; if (!IsChannelName(name) || !strIsIrcCh(name)) { /* bad channel name */ send_reply(sptr, ERR_NOSUCHCHANNEL, name); continue; } if (cli_user(sptr)->joined >= feature_int(FEAT_MAXCHANNELSPERUSER) && !HasPriv(sptr, PRIV_CHAN_LIMIT)) { send_reply(sptr, ERR_TOOMANYCHANNELS, name); break; /* no point processing the other channels */ } /* BADCHANed channel */ if ((gline = gline_find(name, GLINE_BADCHAN | GLINE_EXACT)) && GlineIsActive(gline) && !IsAnOper(sptr)) { send_reply(sptr, ERR_BANNEDFROMCHAN, name); continue; } if (!(chptr = FindChannel(name))) { if (((name[0] == '&') && !feature_bool(FEAT_LOCAL_CHANNELS)) || strlen(name) > IRCD_MIN(CHANNELLEN, feature_int(FEAT_CHANNELLEN))) { send_reply(sptr, ERR_NOSUCHCHANNEL, name); continue; } if (!(chptr = get_channel(sptr, name, CGT_CREATE))) continue; /* Try to add the new channel as a recent target for the user. */ if (check_target_limit(sptr, chptr, chptr->chname, 0)) { chptr->members = 0; destruct_channel(chptr); continue; } joinbuf_join(&create, chptr, CHFL_CHANOP | CHFL_CHANNEL_MANAGER); } else if (find_member_link(chptr, sptr)) { continue; /* already on channel */ } else if (check_target_limit(sptr, chptr, chptr->chname, 0)) { continue; } else { int flags = CHFL_DEOPPED; int err = 0; /* Check Apass/Upass -- since we only ever look at a single * "key" per channel now, this hampers brute force attacks. */ if (key && !strcmp(key, chptr->mode.apass)) flags = CHFL_CHANOP | CHFL_CHANNEL_MANAGER; else if (key && !strcmp(key, chptr->mode.upass)) flags = CHFL_CHANOP; else if (chptr->users == 0 && !chptr->mode.apass[0]) { /* Joining a zombie channel (zannel): give ops and increment TS. */ flags = CHFL_CHANOP; chptr->creationtime++; } else if (IsInvited(sptr, chptr)) { /* Invites bypass these other checks. */ } else if (chptr->mode.mode & MODE_INVITEONLY) err = ERR_INVITEONLYCHAN; else if (chptr->mode.limit && (chptr->users >= chptr->mode.limit)) err = ERR_CHANNELISFULL; else if ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(sptr)) err = ERR_NEEDREGGEDNICK; else if (find_ban(sptr, chptr->banlist)) err = ERR_BANNEDFROMCHAN; else if (*chptr->mode.key && (!key || strcmp(key, chptr->mode.key))) err = ERR_BADCHANNELKEY; /* An oper with WALK_LCHAN privilege can join a local channel * he otherwise could not join by using "OVERRIDE" as the key. * This will generate a HACK(4) notice, but fails if the oper * could normally join the channel. */ if (IsLocalChannel(chptr->chname) && HasPriv(sptr, PRIV_WALK_LCHAN) && !(flags & CHFL_CHANOP) && key && !strcmp(key, "OVERRIDE")) { switch (err) { case 0: if (strcmp(chptr->mode.key, "OVERRIDE") && strcmp(chptr->mode.apass, "OVERRIDE") && strcmp(chptr->mode.upass, "OVERRIDE")) { send_reply(sptr, ERR_DONTCHEAT, chptr->chname); continue; } break; case ERR_INVITEONLYCHAN: err = 'i'; break; case ERR_CHANNELISFULL: err = 'l'; break; case ERR_BANNEDFROMCHAN: err = 'b'; break; case ERR_BADCHANNELKEY: err = 'k'; break; case ERR_NEEDREGGEDNICK: err = 'r'; break; default: err = '?'; break; } /* send accountability notice */ if (err) sendto_opmask_butone(0, SNO_HACK4, "OPER JOIN: %C JOIN %H " "(overriding +%c)", sptr, chptr, err); err = 0; } /* Is there some reason the user may not join? */ if (err) { switch(err) { case ERR_NEEDREGGEDNICK: send_reply(sptr, ERR_NEEDREGGEDNICK, chptr->chname, feature_str(FEAT_URLREG)); break; default: send_reply(sptr, err, chptr->chname); break; } continue; } joinbuf_join(&join, chptr, flags); if (flags & CHFL_CHANOP) { struct ModeBuf mbuf; /* Always let the server op him: this is needed on a net with older servers because they 'destruct' channels immediately when they become empty without sending out a DESTRUCT message. As a result, they would always bounce a mode (as HACK(2)) when the user ops himself. (There is also no particularly good reason to have the user op himself.) */ modebuf_init(&mbuf, &me, cptr, chptr, MODEBUF_DEST_SERVER); modebuf_mode_client(&mbuf, MODE_ADD | MODE_CHANOP, sptr, chptr->mode.apass[0] ? ((flags & CHFL_CHANNEL_MANAGER) ? 0 : 1) : MAXOPLEVEL); modebuf_flush(&mbuf); } } del_invite(sptr, chptr); if (chptr->topic[0]) { send_reply(sptr, RPL_TOPIC, chptr->chname, chptr->topic); send_reply(sptr, RPL_TOPICWHOTIME, chptr->chname, chptr->topic_nick, chptr->topic_time); } do_names(sptr, chptr, NAMES_ALL|NAMES_EON); /* send /names list */ } joinbuf_flush(&join); /* must be first, if there's a JOIN 0 */ joinbuf_flush(&create); return 0; }
void do_join(struct Client *cptr, struct Client *sptr, struct JoinBuf *join, struct JoinBuf *create, char *chan, char *key, int level) { struct Channel *chptr; struct Gline *gline; /* BADCHANed channel */ if ((gline = gline_find(chan, GLINE_BADCHAN | GLINE_EXACT)) && GlineIsActive(gline) && !IsAnOper(sptr)) { send_reply(sptr, ERR_BANNEDFROMCHAN, chan); return; } /* Bouncy +L joins */ if (level > feature_int(FEAT_MAX_BOUNCE)) { sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :*** Couldn't join %s ! - Redirection (+L) setting was too bouncy", sptr, chan); return; } if (!(chptr = FindChannel(chan))) { if (((chan[0] == '&') && !feature_bool(FEAT_LOCAL_CHANNELS)) || strlen(chan) > IRCD_MIN(CHANNELLEN, feature_int(FEAT_CHANNELLEN))) { send_reply(sptr, ERR_NOSUCHCHANNEL, chan); return; } if (feature_bool(FEAT_CHANNEL_CREATE_IRCOPONLY) && !IsAnOper(sptr) && !IsChannelService(sptr)) { send_reply(sptr, ERR_NOSUCHCHANNEL, chan); return; } if (!(chptr = get_channel(sptr, chan, CGT_CREATE))) return; /* Try to add the new channel as a recent target for the user. */ if (check_target_limit(sptr, chptr, chptr->chname, 0)) { chptr->members = 0; destruct_channel(chptr); return; } joinbuf_join(create, chptr, CHFL_CHANOP | CHFL_CHANNEL_MANAGER); } else if (find_member_link(chptr, sptr)) { return; /* already on channel */ } else if (check_target_limit(sptr, chptr, chptr->chname, 0)) { return; } else { int flags = CHFL_DEOPPED; int err = 0; int excepted = 0; int exceptkli = 0; struct Ban *ban = NULL; if (*chptr->mode.redir && (*chptr->mode.redir != '\0')) { if (chptr->users >= chptr->mode.limit) { if (IsNoLink(sptr)) send_reply(sptr, ERR_LINKCHAN, chptr->chname, chptr->mode.redir); else if (!IsChannelName(chptr->mode.redir) || !strIsIrcCh(chptr->mode.redir)) send_reply(sptr, ERR_NOSUCHCHANNEL, chptr->mode.redir); else { send_reply(sptr, ERR_LINKSET, chptr->chname, chptr->chname, chptr->mode.redir); do_join(cptr, sptr, join, create, chptr->mode.redir, key, level+1); } return; } } if (find_ban(sptr, chptr->exceptlist, EBAN_EXCEPTLIST, 0)) { if (feature_bool(FEAT_CHMODE_e_CHMODEEXCEPTION)) exceptkli = 1; excepted = 1; } /* Check Apass/Upass -- since we only ever look at a single * "key" per channel now, this hampers brute force attacks. */ if (feature_bool(FEAT_CHMODE_Z_STRICT) && (chptr->mode.exmode & EXMODE_SSLONLY) && !IsSSL(sptr)) err = ERR_SSLONLYCHAN; else if (key && !strcmp(key, chptr->mode.apass)) flags = CHFL_CHANOP | CHFL_CHANNEL_MANAGER; else if (key && !strcmp(key, chptr->mode.upass)) flags = CHFL_CHANOP; else if (chptr->users == 0 && !chptr->mode.apass[0] && !(chptr->mode.exmode & EXMODE_PERSIST)) { /* Joining a zombie channel (zannel): give ops and increment TS. */ flags = CHFL_CHANOP; chptr->creationtime++; } else if (IsXtraOp(sptr)) { /* XtraOp bypasses all other checks. */ } else if ((chptr->mode.exmode & EXMODE_SSLONLY) && !IsSSL(sptr)) err = ERR_SSLONLYCHAN; else if (IsInvited(sptr, chptr)) { /* Invites bypass these other checks. */ } else if (*chptr->mode.key && (!key || strcmp(key, chptr->mode.key)) && !exceptkli) err = ERR_BADCHANNELKEY; else if (*chptr->mode.key && feature_bool(FEAT_FLEXIBLEKEYS) && (key && !strcmp(key, chptr->mode.key))) { /* Assume key checked by previous condition was found to be correct and allow join because FEAT_FLEXIBLEKEYS was enabled */ } else if ((chptr->mode.mode & MODE_INVITEONLY) && !exceptkli) err = ERR_INVITEONLYCHAN; else if (chptr->mode.limit && (chptr->users >= chptr->mode.limit) && !exceptkli) err = ERR_CHANNELISFULL; else if ((chptr->mode.mode & MODE_REGONLY) && !IsAccount(sptr)) err = ERR_NEEDREGGEDNICK; else if ((chptr->mode.exmode & EXMODE_ADMINONLY) && !IsAdmin(sptr)) err = ERR_ADMINONLYCHAN; else if ((chptr->mode.exmode & EXMODE_OPERONLY) && !IsAnOper(sptr)) err = ERR_OPERONLYCHAN; else if ((ban = find_ban(sptr, chptr->banlist, EBAN_NONE, 0)) && !excepted) err = ERR_BANNEDFROMCHAN; /* An oper with WALK_LCHAN privilege can join a local channel * he otherwise could not join by using "OVERRIDE" as the key. * This will generate a HACK(4) notice, but fails if the oper * could normally join the channel. */ if (IsLocalChannel(chptr->chname) && HasPriv(sptr, PRIV_WALK_LCHAN) && !(flags & CHFL_CHANOP) && key && !strcmp(key, "OVERRIDE")) { switch (err) { case 0: if (strcmp(chptr->mode.key, "OVERRIDE") && strcmp(chptr->mode.apass, "OVERRIDE") && strcmp(chptr->mode.upass, "OVERRIDE")) { send_reply(sptr, ERR_DONTCHEAT, chptr->chname); return; } break; case ERR_INVITEONLYCHAN: err = 'i'; break; case ERR_CHANNELISFULL: err = 'l'; break; case ERR_BANNEDFROMCHAN: err = 'b'; break; case ERR_BADCHANNELKEY: err = 'k'; break; case ERR_NEEDREGGEDNICK: err = 'r'; break; case ERR_ADMINONLYCHAN: err = 'a'; break; case ERR_OPERONLYCHAN: err = 'O'; break; case ERR_SSLONLYCHAN: err = 'Z'; break; default: err = '?'; break; } /* send accountability notice */ if (err) sendto_opmask_butone(0, SNO_HACK4, "OPER JOIN: %C JOIN %H " "(overriding +%c)", sptr, chptr, err); err = 0; } /* Is there some reason the user may not join? */ if (err) { switch(err) { case ERR_NEEDREGGEDNICK: send_reply(sptr, ERR_NEEDREGGEDNICK, chptr->chname, feature_str(FEAT_URLREG)); break; default: send_reply(sptr, err, chptr->chname); break; } return; } joinbuf_join(join, chptr, flags); if (flags & CHFL_CHANOP) { struct ModeBuf mbuf; /* Always let the server op him: this is needed on a net with older servers because they 'destruct' channels immediately when they become empty without sending out a DESTRUCT message. As a result, they would always bounce a mode (as HACK(2)) when the user ops himself. (There is also no particularly good reason to have the user op himself.) */ modebuf_init(&mbuf, &me, cptr, chptr, MODEBUF_DEST_SERVER); modebuf_mode_client(&mbuf, MODE_ADD | MODE_CHANOP, sptr, chptr->mode.apass[0] ? ((flags & CHFL_CHANNEL_MANAGER) ? 0 : 1) : MAXOPLEVEL); modebuf_flush(&mbuf); } } del_invite(sptr, chptr); if (chptr->topic[0]) { send_reply(sptr, RPL_TOPIC, chptr->chname, chptr->topic); send_reply(sptr, RPL_TOPICWHOTIME, chptr->chname, chptr->topic_nick, chptr->topic_time); } do_names(sptr, chptr, NAMES_ALL|NAMES_EON); /* send /names list */ }
void read_message(void *arg) { int fd = *((int *)arg); int to_fd; int count; int result; int temp; struct message msg; struct online *p; struct online *q; struct online *m; while(1) { if((count = read(fd,&msg,sizeof(msg))) != 0) //读取客户端传来的信息 { //printf("aaaaaaaaaaaaa%d\n",msg.action); if(msg.action == log) { p = (struct online*)malloc(sizeof(struct online)); p->fd = fd; p->ID = msg.ID; strcpy(p->passwd,msg.passwd); if(find_id(msg.ID) == 0) //找到已经登录的ID号,返回have_log,防止重复登录 { msg.action = have_log; write(fd,&msg,sizeof(msg)); } else { result = server_log(p); //去数据库中核实登录信息和注册信息是否一致 //printf("bbbbbbbbbbbbb%d\n",result); strcpy(msg.name,p->name); if(result == log_ok) { msg.action = log_ok; insert_online(p); //登录成功后,插入链表,用来显示在线的用户 write(fd,&msg,sizeof(msg)); sleep(8); read_unlog_msg(msg.name,fd); //读保存在服务器里的离线消息 } if(result == admin_log_ok) { msg.action = admin_log_ok; insert_online(p); write(fd,&msg,sizeof(msg)); sleep(8); read_unlog_msg(msg.name,fd); } if(result == passwd_error) { msg.action = passwd_error; write(fd,&msg,sizeof(msg)); } if(result == ID_error) { msg.action = ID_error; write(fd,&msg,sizeof(msg)); } } } if(msg.action == reg) { p = (struct online*)malloc(sizeof(struct online)); //给结构体p分配空间 p->fd = fd; //为写入数据库作准备 strcpy(p->name,msg.name); strcpy(p->passwd,msg.passwd); //result = insert_online(p); //if(result == insert_ok) srand(time(0)); //防止随机数重复 temp = rand(); //生成随机数 p->ID = temp; msg.ID = p->ID; //返回给客户端的ID和reg_ok msg.action = reg_ok; //通知客户端“注册成功”的标志 my_sqlite(p); //注册时的信息写入数据库 write(fd,&msg,sizeof(msg));//把生成的id号传给客户端 } if(msg.action == say) { if(find_ban(fd) == ban) { msg.action = ban; write(fd,&msg,sizeof(msg)); msg.action = -2; //防止和谁聊天,谁被禁言 } else { to_fd = find_fd(msg.toname);//聊天通过寻找对方的fd,找不到返回-1,找到返回对方的fd if(to_fd == -1) { msg.action = to_fd; reserve_unlog_msg(&msg); reserve_chat_msg(&msg); write(fd,&msg,sizeof(msg));//没找到客户2,就返回客户1的fd } else { reserve_chat_msg(&msg); write(to_fd,&msg,sizeof(msg));//找到了客户2,就返回客户2的fd } } } if(msg.action == say_all) { if(find_ban(fd) == ban) { msg.action = ban; write(fd,&msg,sizeof(msg)); msg.action = -2; } else { struct online *temp = head; //遍历链表,传送每一个fd reserve_chat_msg(&msg); while(temp != NULL) { write(temp->fd,&msg,sizeof(msg)); temp = temp->next; } } } if(msg.action == send_face) { if(find_ban(fd) == ban) { msg.action = ban; write(fd,&msg,sizeof(msg)); msg.action = -2; //防止和谁聊天,谁被禁言 } else { to_fd = find_fd(msg.toname); if(to_fd == -1) { msg.action = to_fd; write(fd,&msg,sizeof(msg)); } else { write(to_fd,&msg,sizeof(msg)); } } } if(msg.action == change) { struct online *temp = head; //通过查找ID,替换昵称和密码 q = (struct online*)malloc(sizeof(struct online)); while(temp->fd == fd) { q->ID = msg.ID; strcpy(q->passwd,msg.passwd); strcpy(q->name,msg.name); //printf("aaaaaaaaaa%ldaaaaaaa%saaaaaaa%s\n",q->ID,q->passwd,q->name); result = server_change(q); //printf("cccccccccccccccckui zi shi sha bi!\n"); if(result == change_ok) { msg.action = change_ok; write(fd,&msg,sizeof(msg)); break; } else { msg.action = change_error; write(fd,&msg,sizeof(msg)); break; } temp = temp->next; } } if(msg.action == show) { struct online *temp = head; //遍历链表,传送每一个fd while(temp != NULL) { msg.ID = temp->ID; //错误:这两句话要加,不然信息是同一个人的 my_strcpy(msg.name,temp->name); write(fd,&msg,sizeof(msg)); //错误:这里是fd,是在发过来的客户的界面显示 temp = temp->next; } } if(msg.action == quit) { //printf("aaaaaaaaaaaaa%ld\n",msg.ID); m = (struct online*)malloc(sizeof(struct online)); m->fd = fd; //m->ID = msg.ID; //my_strcpy(m->passwd,msg.passwd); //my_strcpy(m->name,msg.name); //printf("aaaaaaaaaaaaa%ld\n",msg.ID); delete_online(m); //链表中不显示该用户 msg.action = quit_ok; write(fd,&msg,sizeof(msg)); /* if(result == delete_error) { msg.action = quit_error; write(fd,&msg,sizeof(msg)); } */ } if(msg.action == kick) { to_fd = find_fd(msg.toname); //fd = find_fd(msg.name); if(to_fd == -1 || my_strcmp(msg.name,msg.toname) == 0) { msg.action = -1; write(fd,&msg,sizeof(msg)); } else { m = (struct online*)malloc(sizeof(struct online)); m->fd = to_fd; delete_online(m); //链表中不显示该用户 msg.action = kick_ok; write(fd,&msg,sizeof(msg)); write(to_fd,&msg,sizeof(msg)); } } if(msg.action == ban) { //printf("nnnnnnn%s\n",msg.toname); to_fd = find_fd(msg.toname); struct online *temp; struct online *str = head; temp = (struct online*)malloc(sizeof(struct online)); while(str != NULL) { msg.action = ban_tell_all; //不能写在后面,找到了就要发过去 write(str->fd,&msg,sizeof(msg)); if(str->fd == to_fd) { temp->fd = to_fd; temp->ID = str->ID; my_strcpy(temp->name,str->name); //insert_online(temp); 错误:不能插入head中,那是显示在线链表的 insert_ban(temp); //建立一个禁言链表 } str = str->next; } } if(msg.action == solve_ban) { to_fd = find_fd(msg.toname); if((find_ban(to_fd)) == -1) { //printf("aaaaaaaaaaaaaaaaaa\n"); msg.action = solve_error; write(fd,&msg,sizeof(msg)); //printf("aaaaaaaaaaaaaaaaaa\n"); } else { m = (struct online*)malloc(sizeof(struct online)); m->fd = to_fd; delete_ban(m); //删除禁言链表中该用户名字 msg.action = solve_ban; struct online *temp = head; while(temp != NULL) //通知所有人,该用户被解禁了 { write(temp->fd,&msg,sizeof(msg)); temp = temp->next; } } } if(msg.action == see_record) { //printf("cccccccccccccccccccccccccc\n"); read_chat_msg(msg.name,fd); write(fd,&msg,sizeof(msg)); } } else //客户端ctrl+c之后,将在线的用户删除掉,show的时候少掉这个异常退出的用户 { struct online *m = (struct online*)malloc(sizeof(struct online)); m->fd = fd; delete_online(m); } } }