/* ==================== idInterpreter::Execute ==================== */ bool idInterpreter::Execute( void ) { varEval_t var_a; varEval_t var_b; varEval_t var_c; varEval_t var; statement_t *st; int runaway; idThread *newThread; float floatVal; idScriptObject *obj; const function_t *func; if ( threadDying || !currentFunction ) { return true; } if ( multiFrameEvent ) { // move to previous instruction and call it again instructionPointer--; } runaway = 5000000; doneProcessing = false; while( !doneProcessing && !threadDying ) { instructionPointer++; if ( !--runaway ) { Error( "runaway loop error" ); } // next statement st = &gameLocal.program.GetStatement( instructionPointer ); switch( st->op ) { case OP_RETURN: LeaveFunction( st->a ); break; case OP_THREAD: newThread = new idThread( this, st->a->value.functionPtr, st->b->value.argSize ); newThread->Start(); // return the thread number to the script gameLocal.program.ReturnFloat( newThread->GetThreadNum() ); PopParms( st->b->value.argSize ); break; case OP_OBJTHREAD: var_a = GetVariable( st->a ); obj = GetScriptObject( *var_a.entityNumberPtr ); if ( obj ) { func = obj->GetTypeDef()->GetFunction( st->b->value.virtualFunction ); assert( st->c->value.argSize == func->parmTotal ); newThread = new idThread( this, GetEntity( *var_a.entityNumberPtr ), func, func->parmTotal ); newThread->Start(); // return the thread number to the script gameLocal.program.ReturnFloat( newThread->GetThreadNum() ); } else { // return a null thread to the script gameLocal.program.ReturnFloat( 0.0f ); } PopParms( st->c->value.argSize ); break; case OP_CALL: EnterFunction( st->a->value.functionPtr, false ); break; case OP_EVENTCALL: CallEvent( st->a->value.functionPtr, st->b->value.argSize ); break; case OP_OBJECTCALL: var_a = GetVariable( st->a ); obj = GetScriptObject( *var_a.entityNumberPtr ); if ( obj ) { func = obj->GetTypeDef()->GetFunction( st->b->value.virtualFunction ); EnterFunction( func, false ); } else { // return a 'safe' value gameLocal.program.ReturnVector( vec3_zero ); gameLocal.program.ReturnString( "" ); PopParms( st->c->value.argSize ); } break; case OP_SYSCALL: CallSysEvent( st->a->value.functionPtr, st->b->value.argSize ); break; case OP_IFNOT: var_a = GetVariable( st->a ); if ( *var_a.intPtr == 0 ) { NextInstruction( instructionPointer + st->b->value.jumpOffset ); } break; case OP_IF: var_a = GetVariable( st->a ); if ( *var_a.intPtr != 0 ) { NextInstruction( instructionPointer + st->b->value.jumpOffset ); } break; case OP_GOTO: NextInstruction( instructionPointer + st->a->value.jumpOffset ); break; case OP_ADD_F: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = *var_a.floatPtr + *var_b.floatPtr; break; case OP_ADD_V: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.vectorPtr = *var_a.vectorPtr + *var_b.vectorPtr; break; case OP_ADD_S: SetString( st->c, GetString( st->a ) ); AppendString( st->c, GetString( st->b ) ); break; case OP_ADD_FS: var_a = GetVariable( st->a ); SetString( st->c, FloatToString( *var_a.floatPtr ) ); AppendString( st->c, GetString( st->b ) ); break; case OP_ADD_SF: var_b = GetVariable( st->b ); SetString( st->c, GetString( st->a ) ); AppendString( st->c, FloatToString( *var_b.floatPtr ) ); break; case OP_ADD_VS: var_a = GetVariable( st->a ); SetString( st->c, var_a.vectorPtr->ToString() ); AppendString( st->c, GetString( st->b ) ); break; case OP_ADD_SV: var_b = GetVariable( st->b ); SetString( st->c, GetString( st->a ) ); AppendString( st->c, var_b.vectorPtr->ToString() ); break; case OP_SUB_F: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = *var_a.floatPtr - *var_b.floatPtr; break; case OP_SUB_V: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.vectorPtr = *var_a.vectorPtr - *var_b.vectorPtr; break; case OP_MUL_F: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = *var_a.floatPtr * *var_b.floatPtr; break; case OP_MUL_V: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = *var_a.vectorPtr * *var_b.vectorPtr; break; case OP_MUL_FV: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.vectorPtr = *var_a.floatPtr * *var_b.vectorPtr; break; case OP_MUL_VF: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.vectorPtr = *var_a.vectorPtr * *var_b.floatPtr; break; case OP_DIV_F: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); if ( *var_b.floatPtr == 0.0f ) { Warning( "Divide by zero" ); *var_c.floatPtr = idMath::INFINITY; } else { *var_c.floatPtr = *var_a.floatPtr / *var_b.floatPtr; } break; case OP_MOD_F: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable ( st->c ); if ( *var_b.floatPtr == 0.0f ) { Warning( "Divide by zero" ); *var_c.floatPtr = *var_a.floatPtr; } else { *var_c.floatPtr = static_cast<int>( *var_a.floatPtr ) % static_cast<int>( *var_b.floatPtr ); } break; case OP_BITAND: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = static_cast<int>( *var_a.floatPtr ) & static_cast<int>( *var_b.floatPtr ); break; case OP_BITOR: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = static_cast<int>( *var_a.floatPtr ) | static_cast<int>( *var_b.floatPtr ); break; case OP_GE: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = ( *var_a.floatPtr >= *var_b.floatPtr ); break; case OP_LE: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = ( *var_a.floatPtr <= *var_b.floatPtr ); break; case OP_GT: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = ( *var_a.floatPtr > *var_b.floatPtr ); break; case OP_LT: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = ( *var_a.floatPtr < *var_b.floatPtr ); break; case OP_AND: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = ( *var_a.floatPtr != 0.0f ) && ( *var_b.floatPtr != 0.0f ); break; case OP_AND_BOOLF: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = ( *var_a.intPtr != 0 ) && ( *var_b.floatPtr != 0.0f ); break; case OP_AND_FBOOL: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = ( *var_a.floatPtr != 0.0f ) && ( *var_b.intPtr != 0 ); break; case OP_AND_BOOLBOOL: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = ( *var_a.intPtr != 0 ) && ( *var_b.intPtr != 0 ); break; case OP_OR: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = ( *var_a.floatPtr != 0.0f ) || ( *var_b.floatPtr != 0.0f ); break; case OP_OR_BOOLF: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = ( *var_a.intPtr != 0 ) || ( *var_b.floatPtr != 0.0f ); break; case OP_OR_FBOOL: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = ( *var_a.floatPtr != 0.0f ) || ( *var_b.intPtr != 0 ); break; case OP_OR_BOOLBOOL: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = ( *var_a.intPtr != 0 ) || ( *var_b.intPtr != 0 ); break; case OP_NOT_BOOL: var_a = GetVariable( st->a ); var_c = GetVariable( st->c ); *var_c.floatPtr = ( *var_a.intPtr == 0 ); break; case OP_NOT_F: var_a = GetVariable( st->a ); var_c = GetVariable( st->c ); *var_c.floatPtr = ( *var_a.floatPtr == 0.0f ); break; case OP_NOT_V: var_a = GetVariable( st->a ); var_c = GetVariable( st->c ); *var_c.floatPtr = ( *var_a.vectorPtr == vec3_zero ); break; case OP_NOT_S: var_c = GetVariable( st->c ); *var_c.floatPtr = ( strlen( GetString( st->a ) ) == 0 ); break; case OP_NOT_ENT: var_a = GetVariable( st->a ); var_c = GetVariable( st->c ); *var_c.floatPtr = ( GetEntity( *var_a.entityNumberPtr ) == NULL ); break; case OP_NEG_F: var_a = GetVariable( st->a ); var_c = GetVariable( st->c ); *var_c.floatPtr = -*var_a.floatPtr; break; case OP_NEG_V: var_a = GetVariable( st->a ); var_c = GetVariable( st->c ); *var_c.vectorPtr = -*var_a.vectorPtr; break; case OP_INT_F: var_a = GetVariable( st->a ); var_c = GetVariable( st->c ); *var_c.floatPtr = static_cast<int>( *var_a.floatPtr ); break; case OP_EQ_F: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = ( *var_a.floatPtr == *var_b.floatPtr ); break; case OP_EQ_V: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = ( *var_a.vectorPtr == *var_b.vectorPtr ); break; case OP_EQ_S: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = ( idStr::Cmp( GetString( st->a ), GetString( st->b ) ) == 0 ); break; case OP_EQ_E: case OP_EQ_EO: case OP_EQ_OE: case OP_EQ_OO: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = ( *var_a.entityNumberPtr == *var_b.entityNumberPtr ); break; case OP_NE_F: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = ( *var_a.floatPtr != *var_b.floatPtr ); break; case OP_NE_V: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = ( *var_a.vectorPtr != *var_b.vectorPtr ); break; case OP_NE_S: var_c = GetVariable( st->c ); *var_c.floatPtr = ( idStr::Cmp( GetString( st->a ), GetString( st->b ) ) != 0 ); break; case OP_NE_E: case OP_NE_EO: case OP_NE_OE: case OP_NE_OO: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = ( *var_a.entityNumberPtr != *var_b.entityNumberPtr ); break; case OP_UADD_F: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); *var_b.floatPtr += *var_a.floatPtr; break; case OP_UADD_V: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); *var_b.vectorPtr += *var_a.vectorPtr; break; case OP_USUB_F: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); *var_b.floatPtr -= *var_a.floatPtr; break; case OP_USUB_V: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); *var_b.vectorPtr -= *var_a.vectorPtr; break; case OP_UMUL_F: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); *var_b.floatPtr *= *var_a.floatPtr; break; case OP_UMUL_V: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); *var_b.vectorPtr *= *var_a.floatPtr; break; case OP_UDIV_F: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); if ( *var_a.floatPtr == 0.0f ) { Warning( "Divide by zero" ); *var_b.floatPtr = idMath::INFINITY; } else { *var_b.floatPtr = *var_b.floatPtr / *var_a.floatPtr; } break; case OP_UDIV_V: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); if ( *var_a.floatPtr == 0.0f ) { Warning( "Divide by zero" ); var_b.vectorPtr->Set( idMath::INFINITY, idMath::INFINITY, idMath::INFINITY ); } else { *var_b.vectorPtr = *var_b.vectorPtr / *var_a.floatPtr; } break; case OP_UMOD_F: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); if ( *var_a.floatPtr == 0.0f ) { Warning( "Divide by zero" ); *var_b.floatPtr = *var_a.floatPtr; } else { *var_b.floatPtr = static_cast<int>( *var_b.floatPtr ) % static_cast<int>( *var_a.floatPtr ); } break; case OP_UOR_F: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); *var_b.floatPtr = static_cast<int>( *var_b.floatPtr ) | static_cast<int>( *var_a.floatPtr ); break; case OP_UAND_F: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); *var_b.floatPtr = static_cast<int>( *var_b.floatPtr ) & static_cast<int>( *var_a.floatPtr ); break; case OP_UINC_F: var_a = GetVariable( st->a ); ( *var_a.floatPtr )++; break; case OP_UINCP_F: var_a = GetVariable( st->a ); obj = GetScriptObject( *var_a.entityNumberPtr ); if ( obj ) { var.bytePtr = &obj->data[ st->b->value.ptrOffset ]; ( *var.floatPtr )++; } break; case OP_UDEC_F: var_a = GetVariable( st->a ); ( *var_a.floatPtr )--; break; case OP_UDECP_F: var_a = GetVariable( st->a ); obj = GetScriptObject( *var_a.entityNumberPtr ); if ( obj ) { var.bytePtr = &obj->data[ st->b->value.ptrOffset ]; ( *var.floatPtr )--; } break; case OP_COMP_F: var_a = GetVariable( st->a ); var_c = GetVariable( st->c ); *var_c.floatPtr = ~static_cast<int>( *var_a.floatPtr ); break; case OP_STORE_F: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); *var_b.floatPtr = *var_a.floatPtr; break; case OP_STORE_ENT: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); *var_b.entityNumberPtr = *var_a.entityNumberPtr; break; case OP_STORE_BOOL: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); *var_b.intPtr = *var_a.intPtr; break; case OP_STORE_OBJENT: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); obj = GetScriptObject( *var_a.entityNumberPtr ); if ( !obj ) { *var_b.entityNumberPtr = 0; } else if ( !obj->GetTypeDef()->Inherits( st->b->TypeDef() ) ) { //Warning( "object '%s' cannot be converted to '%s'", obj->GetTypeName(), st->b->TypeDef()->Name() ); *var_b.entityNumberPtr = 0; } else { *var_b.entityNumberPtr = *var_a.entityNumberPtr; } break; case OP_STORE_OBJ: case OP_STORE_ENTOBJ: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); *var_b.entityNumberPtr = *var_a.entityNumberPtr; break; case OP_STORE_S: SetString( st->b, GetString( st->a ) ); break; case OP_STORE_V: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); *var_b.vectorPtr = *var_a.vectorPtr; break; case OP_STORE_FTOS: var_a = GetVariable( st->a ); SetString( st->b, FloatToString( *var_a.floatPtr ) ); break; case OP_STORE_BTOS: var_a = GetVariable( st->a ); SetString( st->b, *var_a.intPtr ? "true" : "false" ); break; case OP_STORE_VTOS: var_a = GetVariable( st->a ); SetString( st->b, var_a.vectorPtr->ToString() ); break; case OP_STORE_FTOBOOL: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); if ( *var_a.floatPtr != 0.0f ) { *var_b.intPtr = 1; } else { *var_b.intPtr = 0; } break; case OP_STORE_BOOLTOF: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); *var_b.floatPtr = static_cast<float>( *var_a.intPtr ); break; case OP_STOREP_F: var_b = GetVariable( st->b ); if ( var_b.evalPtr && var_b.evalPtr->floatPtr ) { var_a = GetVariable( st->a ); *var_b.evalPtr->floatPtr = *var_a.floatPtr; } break; case OP_STOREP_ENT: var_b = GetVariable( st->b ); if ( var_b.evalPtr && var_b.evalPtr->entityNumberPtr ) { var_a = GetVariable( st->a ); *var_b.evalPtr->entityNumberPtr = *var_a.entityNumberPtr; } break; case OP_STOREP_FLD: var_b = GetVariable( st->b ); if ( var_b.evalPtr && var_b.evalPtr->intPtr ) { var_a = GetVariable( st->a ); *var_b.evalPtr->intPtr = *var_a.intPtr; } break; case OP_STOREP_BOOL: var_b = GetVariable( st->b ); if ( var_b.evalPtr && var_b.evalPtr->intPtr ) { var_a = GetVariable( st->a ); *var_b.evalPtr->intPtr = *var_a.intPtr; } break; case OP_STOREP_S: var_b = GetVariable( st->b ); if ( var_b.evalPtr && var_b.evalPtr->stringPtr ) { idStr::Copynz( var_b.evalPtr->stringPtr, GetString( st->a ), MAX_STRING_LEN ); } break; case OP_STOREP_V: var_b = GetVariable( st->b ); if ( var_b.evalPtr && var_b.evalPtr->vectorPtr ) { var_a = GetVariable( st->a ); *var_b.evalPtr->vectorPtr = *var_a.vectorPtr; } break; case OP_STOREP_FTOS: var_b = GetVariable( st->b ); if ( var_b.evalPtr && var_b.evalPtr->stringPtr ) { var_a = GetVariable( st->a ); idStr::Copynz( var_b.evalPtr->stringPtr, FloatToString( *var_a.floatPtr ), MAX_STRING_LEN ); } break; case OP_STOREP_BTOS: var_b = GetVariable( st->b ); if ( var_b.evalPtr && var_b.evalPtr->stringPtr ) { var_a = GetVariable( st->a ); if ( *var_a.floatPtr != 0.0f ) { idStr::Copynz( var_b.evalPtr->stringPtr, "true", MAX_STRING_LEN ); } else { idStr::Copynz( var_b.evalPtr->stringPtr, "false", MAX_STRING_LEN ); } } break; case OP_STOREP_VTOS: var_b = GetVariable( st->b ); if ( var_b.evalPtr && var_b.evalPtr->stringPtr ) { var_a = GetVariable( st->a ); idStr::Copynz( var_b.evalPtr->stringPtr, var_a.vectorPtr->ToString(), MAX_STRING_LEN ); } break; case OP_STOREP_FTOBOOL: var_b = GetVariable( st->b ); if ( var_b.evalPtr && var_b.evalPtr->intPtr ) { var_a = GetVariable( st->a ); if ( *var_a.floatPtr != 0.0f ) { *var_b.evalPtr->intPtr = 1; } else { *var_b.evalPtr->intPtr = 0; } } break; case OP_STOREP_BOOLTOF: var_b = GetVariable( st->b ); if ( var_b.evalPtr && var_b.evalPtr->floatPtr ) { var_a = GetVariable( st->a ); *var_b.evalPtr->floatPtr = static_cast<float>( *var_a.intPtr ); } break; case OP_STOREP_OBJ: var_b = GetVariable( st->b ); if ( var_b.evalPtr && var_b.evalPtr->entityNumberPtr ) { var_a = GetVariable( st->a ); *var_b.evalPtr->entityNumberPtr = *var_a.entityNumberPtr; } break; case OP_STOREP_OBJENT: var_b = GetVariable( st->b ); if ( var_b.evalPtr && var_b.evalPtr->entityNumberPtr ) { var_a = GetVariable( st->a ); obj = GetScriptObject( *var_a.entityNumberPtr ); if ( !obj ) { *var_b.evalPtr->entityNumberPtr = 0; // st->b points to type_pointer, which is just a temporary that gets its type reassigned, so we store the real type in st->c // so that we can do a type check during run time since we don't know what type the script object is at compile time because it // comes from an entity } else if ( !obj->GetTypeDef()->Inherits( st->c->TypeDef() ) ) { //Warning( "object '%s' cannot be converted to '%s'", obj->GetTypeName(), st->c->TypeDef()->Name() ); *var_b.evalPtr->entityNumberPtr = 0; } else { *var_b.evalPtr->entityNumberPtr = *var_a.entityNumberPtr; } } break; case OP_ADDRESS: var_a = GetVariable( st->a ); var_c = GetVariable( st->c ); obj = GetScriptObject( *var_a.entityNumberPtr ); if ( obj ) { var_c.evalPtr->bytePtr = &obj->data[ st->b->value.ptrOffset ]; } else { var_c.evalPtr->bytePtr = NULL; } break; case OP_INDIRECT_F: var_a = GetVariable( st->a ); var_c = GetVariable( st->c ); obj = GetScriptObject( *var_a.entityNumberPtr ); if ( obj ) { var.bytePtr = &obj->data[ st->b->value.ptrOffset ]; *var_c.floatPtr = *var.floatPtr; } else { *var_c.floatPtr = 0.0f; } break; case OP_INDIRECT_ENT: var_a = GetVariable( st->a ); var_c = GetVariable( st->c ); obj = GetScriptObject( *var_a.entityNumberPtr ); if ( obj ) { var.bytePtr = &obj->data[ st->b->value.ptrOffset ]; *var_c.entityNumberPtr = *var.entityNumberPtr; } else { *var_c.entityNumberPtr = 0; } break; case OP_INDIRECT_BOOL: var_a = GetVariable( st->a ); var_c = GetVariable( st->c ); obj = GetScriptObject( *var_a.entityNumberPtr ); if ( obj ) { var.bytePtr = &obj->data[ st->b->value.ptrOffset ]; *var_c.intPtr = *var.intPtr; } else { *var_c.intPtr = 0; } break; case OP_INDIRECT_S: var_a = GetVariable( st->a ); obj = GetScriptObject( *var_a.entityNumberPtr ); if ( obj ) { var.bytePtr = &obj->data[ st->b->value.ptrOffset ]; SetString( st->c, var.stringPtr ); } else { SetString( st->c, "" ); } break; case OP_INDIRECT_V: var_a = GetVariable( st->a ); var_c = GetVariable( st->c ); obj = GetScriptObject( *var_a.entityNumberPtr ); if ( obj ) { var.bytePtr = &obj->data[ st->b->value.ptrOffset ]; *var_c.vectorPtr = *var.vectorPtr; } else { var_c.vectorPtr->Zero(); } break; case OP_INDIRECT_OBJ: var_a = GetVariable( st->a ); var_c = GetVariable( st->c ); obj = GetScriptObject( *var_a.entityNumberPtr ); if ( !obj ) { *var_c.entityNumberPtr = 0; } else { var.bytePtr = &obj->data[ st->b->value.ptrOffset ]; *var_c.entityNumberPtr = *var.entityNumberPtr; } break; case OP_PUSH_F: var_a = GetVariable( st->a ); Push( *var_a.intPtr ); break; case OP_PUSH_FTOS: var_a = GetVariable( st->a ); PushString( FloatToString( *var_a.floatPtr ) ); break; case OP_PUSH_BTOF: var_a = GetVariable( st->a ); floatVal = *var_a.intPtr; Push( *reinterpret_cast<int *>( &floatVal ) ); break; case OP_PUSH_FTOB: var_a = GetVariable( st->a ); if ( *var_a.floatPtr != 0.0f ) { Push( 1 ); } else { Push( 0 ); } break; case OP_PUSH_VTOS: var_a = GetVariable( st->a ); PushString( var_a.vectorPtr->ToString() ); break; case OP_PUSH_BTOS: var_a = GetVariable( st->a ); PushString( *var_a.intPtr ? "true" : "false" ); break; case OP_PUSH_ENT: var_a = GetVariable( st->a ); Push( *var_a.entityNumberPtr ); break; case OP_PUSH_S: PushString( GetString( st->a ) ); break; case OP_PUSH_V: var_a = GetVariable( st->a ); Push( *reinterpret_cast<int *>( &var_a.vectorPtr->x ) ); Push( *reinterpret_cast<int *>( &var_a.vectorPtr->y ) ); Push( *reinterpret_cast<int *>( &var_a.vectorPtr->z ) ); break; case OP_PUSH_OBJ: var_a = GetVariable( st->a ); Push( *var_a.entityNumberPtr ); break; case OP_PUSH_OBJENT: var_a = GetVariable( st->a ); Push( *var_a.entityNumberPtr ); break; case OP_BREAK: case OP_CONTINUE: default: Error( "Bad opcode %i", st->op ); break; } } return threadDying; }
/* * IP Tunneling transmitter * * This function encapsulates the packet in a new IP packet, its * destination will be set to cp->daddr. Most code of this function * is taken from ipip.c. * * It is used in VS/TUN cluster. The load balancer selects a real * server from a cluster based on a scheduling algorithm, * encapsulates the request packet and forwards it to the selected * server. For example, all real servers are configured with * "ifconfig tunl0 <Virtual IP Address> up". When the server receives * the encapsulated packet, it will decapsulate the packet, processe * the request and return the response packets directly to the client * without passing the load balancer. This can greatly increase the * scalability of virtual server. * * Used for ANY protocol */ int ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp) { struct rtable *rt; /* Route to the other host */ __be32 saddr; /* Source for tunnel */ struct net_device *tdev; /* Device to other host */ struct iphdr *old_iph = ip_hdr(skb); u8 tos = old_iph->tos; __be16 df = old_iph->frag_off; struct iphdr *iph; /* Our new IP header */ unsigned int max_headroom; /* The extra header space needed */ int mtu; int ret; EnterFunction(10); if (!(rt = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip, RT_TOS(tos), IP_VS_RT_MODE_LOCAL | IP_VS_RT_MODE_NON_LOCAL, &saddr))) goto tx_error_icmp; if (rt->rt_flags & RTCF_LOCAL) { ip_rt_put(rt); IP_VS_XMIT(NFPROTO_IPV4, skb, cp, 1); } tdev = rt->dst.dev; mtu = dst_mtu(&rt->dst) - sizeof(struct iphdr); if (mtu < 68) { IP_VS_DBG_RL("%s(): mtu less than 68\n", __func__); goto tx_error_put; } if (skb_dst(skb)) skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu); df |= (old_iph->frag_off & htons(IP_DF)); if ((old_iph->frag_off & htons(IP_DF) && mtu < ntohs(old_iph->tot_len) && !skb_is_gso(skb))) { icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu)); IP_VS_DBG_RL("%s(): frag needed\n", __func__); goto tx_error_put; } /* * Okay, now see if we can stuff it in the buffer as-is. */ max_headroom = LL_RESERVED_SPACE(tdev) + sizeof(struct iphdr); if (skb_headroom(skb) < max_headroom || skb_cloned(skb) || skb_shared(skb)) { struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom); if (!new_skb) { ip_rt_put(rt); kfree_skb(skb); IP_VS_ERR_RL("%s(): no memory\n", __func__); return NF_STOLEN; } kfree_skb(skb); skb = new_skb; old_iph = ip_hdr(skb); } skb->transport_header = skb->network_header; /* fix old IP header checksum */ ip_send_check(old_iph); skb_push(skb, sizeof(struct iphdr)); skb_reset_network_header(skb); memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); /* drop old route */ skb_dst_drop(skb); skb_dst_set(skb, &rt->dst); /* * Push down and install the IPIP header. */ iph = ip_hdr(skb); iph->version = 4; iph->ihl = sizeof(struct iphdr)>>2; iph->frag_off = df; iph->protocol = IPPROTO_IPIP; iph->tos = tos; iph->daddr = cp->daddr.ip; iph->saddr = saddr; iph->ttl = old_iph->ttl; ip_select_ident(iph, &rt->dst, NULL); /* Another hack: avoid icmp_send in ip_fragment */ skb->local_df = 1; ret = IP_VS_XMIT_TUNNEL(skb, cp); if (ret == NF_ACCEPT) ip_local_out(skb); else if (ret == NF_DROP) kfree_skb(skb); LeaveFunction(10); return NF_STOLEN; tx_error_icmp: dst_link_failure(skb); tx_error: kfree_skb(skb); LeaveFunction(10); return NF_STOLEN; tx_error_put: ip_rt_put(rt); goto tx_error; }
int ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp) { struct rt6_info *rt; /* Route to the other host */ struct in6_addr saddr; /* Source for tunnel */ struct net_device *tdev; /* Device to other host */ struct ipv6hdr *old_iph = ipv6_hdr(skb); struct ipv6hdr *iph; /* Our new IP header */ unsigned int max_headroom; /* The extra header space needed */ int mtu; int ret; EnterFunction(10); if (!(rt = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, &saddr, 1, (IP_VS_RT_MODE_LOCAL | IP_VS_RT_MODE_NON_LOCAL)))) goto tx_error_icmp; if (__ip_vs_is_local_route6(rt)) { dst_release(&rt->dst); IP_VS_XMIT(NFPROTO_IPV6, skb, cp, 1); } tdev = rt->dst.dev; mtu = dst_mtu(&rt->dst) - sizeof(struct ipv6hdr); if (mtu < IPV6_MIN_MTU) { IP_VS_DBG_RL("%s(): mtu less than %d\n", __func__, IPV6_MIN_MTU); goto tx_error_put; } if (skb_dst(skb)) skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu); if (mtu < ntohs(old_iph->payload_len) + sizeof(struct ipv6hdr) && !skb_is_gso(skb)) { if (!skb->dev) { struct net *net = dev_net(skb_dst(skb)->dev); skb->dev = net->loopback_dev; } icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); IP_VS_DBG_RL("%s(): frag needed\n", __func__); goto tx_error_put; } /* * Okay, now see if we can stuff it in the buffer as-is. */ max_headroom = LL_RESERVED_SPACE(tdev) + sizeof(struct ipv6hdr); if (skb_headroom(skb) < max_headroom || skb_cloned(skb) || skb_shared(skb)) { struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom); if (!new_skb) { dst_release(&rt->dst); kfree_skb(skb); IP_VS_ERR_RL("%s(): no memory\n", __func__); return NF_STOLEN; } kfree_skb(skb); skb = new_skb; old_iph = ipv6_hdr(skb); } skb->transport_header = skb->network_header; skb_push(skb, sizeof(struct ipv6hdr)); skb_reset_network_header(skb); memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); /* drop old route */ skb_dst_drop(skb); skb_dst_set(skb, &rt->dst); /* * Push down and install the IPIP header. */ iph = ipv6_hdr(skb); iph->version = 6; iph->nexthdr = IPPROTO_IPV6; iph->payload_len = old_iph->payload_len; be16_add_cpu(&iph->payload_len, sizeof(*old_iph)); iph->priority = old_iph->priority; memset(&iph->flow_lbl, 0, sizeof(iph->flow_lbl)); ipv6_addr_copy(&iph->daddr, &cp->daddr.in6); ipv6_addr_copy(&iph->saddr, &saddr); iph->hop_limit = old_iph->hop_limit; /* Another hack: avoid icmp_send in ip_fragment */ skb->local_df = 1; ret = IP_VS_XMIT_TUNNEL(skb, cp); if (ret == NF_ACCEPT) ip6_local_out(skb); else if (ret == NF_DROP) kfree_skb(skb); LeaveFunction(10); return NF_STOLEN; tx_error_icmp: dst_link_failure(skb); tx_error: kfree_skb(skb); LeaveFunction(10); return NF_STOLEN; tx_error_put: dst_release(&rt->dst); goto tx_error; }
/* * NAT transmitter (only for outside-to-inside nat forwarding) * Not used for related ICMP */ int ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp) { struct rtable *rt; /* Route to the other host */ int mtu; struct iphdr *iph = ip_hdr(skb); int local; EnterFunction(10); /* check if it is a connection of no-client-port */ if (unlikely(cp->flags & IP_VS_CONN_F_NO_CPORT)) { __be16 _pt, *p; p = skb_header_pointer(skb, iph->ihl*4, sizeof(_pt), &_pt); if (p == NULL) goto tx_error; ip_vs_conn_fill_cport(cp, *p); IP_VS_DBG(10, "filled cport=%d\n", ntohs(*p)); } if (!(rt = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip, RT_TOS(iph->tos), IP_VS_RT_MODE_LOCAL | IP_VS_RT_MODE_NON_LOCAL | IP_VS_RT_MODE_RDR, NULL))) goto tx_error_icmp; local = rt->rt_flags & RTCF_LOCAL; /* * Avoid duplicate tuple in reply direction for NAT traffic * to local address when connection is sync-ed */ #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) if (cp->flags & IP_VS_CONN_F_SYNC && local) { enum ip_conntrack_info ctinfo; struct nf_conn *ct = ct = nf_ct_get(skb, &ctinfo); if (ct && !nf_ct_is_untracked(ct)) { IP_VS_DBG_RL_PKT(10, AF_INET, pp, skb, 0, "ip_vs_nat_xmit(): " "stopping DNAT to local address"); goto tx_error_put; } } #endif /* From world but DNAT to loopback address? */ if (local && ipv4_is_loopback(cp->daddr.ip) && rt_is_input_route(skb_rtable(skb))) { IP_VS_DBG_RL_PKT(1, AF_INET, pp, skb, 0, "ip_vs_nat_xmit(): " "stopping DNAT to loopback address"); goto tx_error_put; } /* MTU checking */ mtu = dst_mtu(&rt->dst); if ((skb->len > mtu) && (iph->frag_off & htons(IP_DF)) && !skb_is_gso(skb)) { icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu)); IP_VS_DBG_RL_PKT(0, AF_INET, pp, skb, 0, "ip_vs_nat_xmit(): frag needed for"); goto tx_error_put; } /* copy-on-write the packet before mangling it */ if (!skb_make_writable(skb, sizeof(struct iphdr))) goto tx_error_put; if (skb_cow(skb, rt->dst.dev->hard_header_len)) goto tx_error_put; /* mangle the packet */ if (pp->dnat_handler && !pp->dnat_handler(skb, pp, cp)) goto tx_error_put; ip_hdr(skb)->daddr = cp->daddr.ip; ip_send_check(ip_hdr(skb)); if (!local) { /* drop old route */ skb_dst_drop(skb); skb_dst_set(skb, &rt->dst); } else { ip_rt_put(rt); /* * Some IPv4 replies get local address from routes, * not from iph, so while we DNAT after routing * we need this second input/output route. */ if (!__ip_vs_reroute_locally(skb)) goto tx_error; } IP_VS_DBG_PKT(10, AF_INET, pp, skb, 0, "After DNAT"); /* FIXME: when application helper enlarges the packet and the length is larger than the MTU of outgoing device, there will be still MTU problem. */ /* Another hack: avoid icmp_send in ip_fragment */ skb->local_df = 1; IP_VS_XMIT_NAT(NFPROTO_IPV4, skb, cp, local); LeaveFunction(10); return NF_STOLEN; tx_error_icmp: dst_link_failure(skb); tx_error: kfree_skb(skb); LeaveFunction(10); return NF_STOLEN; tx_error_put: ip_rt_put(rt); goto tx_error; }
int ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp) { struct rt6_info *rt; /* Route to the other host */ int mtu; int local; EnterFunction(10); /* check if it is a connection of no-client-port */ if (unlikely(cp->flags & IP_VS_CONN_F_NO_CPORT)) { __be16 _pt, *p; p = skb_header_pointer(skb, sizeof(struct ipv6hdr), sizeof(_pt), &_pt); if (p == NULL) goto tx_error; ip_vs_conn_fill_cport(cp, *p); IP_VS_DBG(10, "filled cport=%d\n", ntohs(*p)); } if (!(rt = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, NULL, 0, (IP_VS_RT_MODE_LOCAL | IP_VS_RT_MODE_NON_LOCAL | IP_VS_RT_MODE_RDR)))) goto tx_error_icmp; local = __ip_vs_is_local_route6(rt); /* * Avoid duplicate tuple in reply direction for NAT traffic * to local address when connection is sync-ed */ #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) if (cp->flags & IP_VS_CONN_F_SYNC && local) { enum ip_conntrack_info ctinfo; struct nf_conn *ct = ct = nf_ct_get(skb, &ctinfo); if (ct && !nf_ct_is_untracked(ct)) { IP_VS_DBG_RL_PKT(10, AF_INET6, pp, skb, 0, "ip_vs_nat_xmit_v6(): " "stopping DNAT to local address"); goto tx_error_put; } } #endif /* From world but DNAT to loopback address? */ if (local && skb->dev && !(skb->dev->flags & IFF_LOOPBACK) && ipv6_addr_type(&rt->rt6i_dst.addr) & IPV6_ADDR_LOOPBACK) { IP_VS_DBG_RL_PKT(1, AF_INET6, pp, skb, 0, "ip_vs_nat_xmit_v6(): " "stopping DNAT to loopback address"); goto tx_error_put; } /* MTU checking */ mtu = dst_mtu(&rt->dst); if (skb->len > mtu && !skb_is_gso(skb)) { if (!skb->dev) { struct net *net = dev_net(skb_dst(skb)->dev); skb->dev = net->loopback_dev; } icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); IP_VS_DBG_RL_PKT(0, AF_INET6, pp, skb, 0, "ip_vs_nat_xmit_v6(): frag needed for"); goto tx_error_put; } /* copy-on-write the packet before mangling it */ if (!skb_make_writable(skb, sizeof(struct ipv6hdr))) goto tx_error_put; if (skb_cow(skb, rt->dst.dev->hard_header_len)) goto tx_error_put; /* mangle the packet */ if (pp->dnat_handler && !pp->dnat_handler(skb, pp, cp)) goto tx_error; ipv6_addr_copy(&ipv6_hdr(skb)->daddr, &cp->daddr.in6); if (!local || !skb->dev) { /* drop the old route when skb is not shared */ skb_dst_drop(skb); skb_dst_set(skb, &rt->dst); } else { /* destined to loopback, do we need to change route? */ dst_release(&rt->dst); } IP_VS_DBG_PKT(10, AF_INET6, pp, skb, 0, "After DNAT"); /* FIXME: when application helper enlarges the packet and the length is larger than the MTU of outgoing device, there will be still MTU problem. */ /* Another hack: avoid icmp_send in ip_fragment */ skb->local_df = 1; IP_VS_XMIT_NAT(NFPROTO_IPV6, skb, cp, local); LeaveFunction(10); return NF_STOLEN; tx_error_icmp: dst_link_failure(skb); tx_error: LeaveFunction(10); kfree_skb(skb); return NF_STOLEN; tx_error_put: dst_release(&rt->dst); goto tx_error; }
/* * ICMP packet transmitter * called by the ip_vs_in_icmp */ int ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp, int offset, unsigned int hooknum) { struct rtable *rt; /* Route to the other host */ int mtu; int rc; int local; int rt_mode; EnterFunction(10); /* The ICMP packet for VS/TUN, VS/DR and LOCALNODE will be forwarded directly here, because there is no need to translate address/port back */ if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ) { if (cp->packet_xmit) rc = cp->packet_xmit(skb, cp, pp); else rc = NF_ACCEPT; /* do not touch skb anymore */ atomic_inc(&cp->in_pkts); goto out; } /* * mangle and send the packet here (only for VS/NAT) */ /* LOCALNODE from FORWARD hook is not supported */ rt_mode = (hooknum != NF_INET_FORWARD) ? IP_VS_RT_MODE_LOCAL | IP_VS_RT_MODE_NON_LOCAL | IP_VS_RT_MODE_RDR : IP_VS_RT_MODE_NON_LOCAL; if (!(rt = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip, RT_TOS(ip_hdr(skb)->tos), rt_mode, NULL))) goto tx_error_icmp; local = rt->rt_flags & RTCF_LOCAL; /* * Avoid duplicate tuple in reply direction for NAT traffic * to local address when connection is sync-ed */ #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) if (cp->flags & IP_VS_CONN_F_SYNC && local) { enum ip_conntrack_info ctinfo; struct nf_conn *ct = ct = nf_ct_get(skb, &ctinfo); if (ct && !nf_ct_is_untracked(ct)) { IP_VS_DBG(10, "%s(): " "stopping DNAT to local address %pI4\n", __func__, &cp->daddr.ip); goto tx_error_put; } } #endif /* From world but DNAT to loopback address? */ if (local && ipv4_is_loopback(cp->daddr.ip) && rt_is_input_route(skb_rtable(skb))) { IP_VS_DBG(1, "%s(): " "stopping DNAT to loopback %pI4\n", __func__, &cp->daddr.ip); goto tx_error_put; } /* MTU checking */ mtu = dst_mtu(&rt->dst); if ((skb->len > mtu) && (ip_hdr(skb)->frag_off & htons(IP_DF)) && !skb_is_gso(skb)) { icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu)); IP_VS_DBG_RL("%s(): frag needed\n", __func__); goto tx_error_put; } /* copy-on-write the packet before mangling it */ if (!skb_make_writable(skb, offset)) goto tx_error_put; if (skb_cow(skb, rt->dst.dev->hard_header_len)) goto tx_error_put; ip_vs_nat_icmp(skb, pp, cp, 0); if (!local) { /* drop the old route when skb is not shared */ skb_dst_drop(skb); skb_dst_set(skb, &rt->dst); } else { ip_rt_put(rt); /* * Some IPv4 replies get local address from routes, * not from iph, so while we DNAT after routing * we need this second input/output route. */ if (!__ip_vs_reroute_locally(skb)) goto tx_error; } /* Another hack: avoid icmp_send in ip_fragment */ skb->local_df = 1; IP_VS_XMIT_NAT(NFPROTO_IPV4, skb, cp, local); rc = NF_STOLEN; goto out; tx_error_icmp: dst_link_failure(skb); tx_error: dev_kfree_skb(skb); rc = NF_STOLEN; out: LeaveFunction(10); return rc; tx_error_put: ip_rt_put(rt); goto tx_error; }
int ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp, int offset, unsigned int hooknum) { struct rt6_info *rt; /* Route to the other host */ int mtu; int rc; int local; int rt_mode; EnterFunction(10); /* The ICMP packet for VS/TUN, VS/DR and LOCALNODE will be forwarded directly here, because there is no need to translate address/port back */ if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ) { if (cp->packet_xmit) rc = cp->packet_xmit(skb, cp, pp); else rc = NF_ACCEPT; /* do not touch skb anymore */ atomic_inc(&cp->in_pkts); goto out; } /* * mangle and send the packet here (only for VS/NAT) */ /* LOCALNODE from FORWARD hook is not supported */ rt_mode = (hooknum != NF_INET_FORWARD) ? IP_VS_RT_MODE_LOCAL | IP_VS_RT_MODE_NON_LOCAL | IP_VS_RT_MODE_RDR : IP_VS_RT_MODE_NON_LOCAL; if (!(rt = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, NULL, 0, rt_mode))) goto tx_error_icmp; local = __ip_vs_is_local_route6(rt); /* * Avoid duplicate tuple in reply direction for NAT traffic * to local address when connection is sync-ed */ #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) if (cp->flags & IP_VS_CONN_F_SYNC && local) { enum ip_conntrack_info ctinfo; struct nf_conn *ct = ct = nf_ct_get(skb, &ctinfo); if (ct && !nf_ct_is_untracked(ct)) { IP_VS_DBG(10, "%s(): " "stopping DNAT to local address %pI6\n", __func__, &cp->daddr.in6); goto tx_error_put; } } #endif /* From world but DNAT to loopback address? */ if (local && skb->dev && !(skb->dev->flags & IFF_LOOPBACK) && ipv6_addr_type(&rt->rt6i_dst.addr) & IPV6_ADDR_LOOPBACK) { IP_VS_DBG(1, "%s(): " "stopping DNAT to loopback %pI6\n", __func__, &cp->daddr.in6); goto tx_error_put; } /* MTU checking */ mtu = dst_mtu(&rt->dst); if (skb->len > mtu && !skb_is_gso(skb)) { if (!skb->dev) { struct net *net = dev_net(skb_dst(skb)->dev); skb->dev = net->loopback_dev; } icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); IP_VS_DBG_RL("%s(): frag needed\n", __func__); goto tx_error_put; } /* copy-on-write the packet before mangling it */ if (!skb_make_writable(skb, offset)) goto tx_error_put; if (skb_cow(skb, rt->dst.dev->hard_header_len)) goto tx_error_put; ip_vs_nat_icmp_v6(skb, pp, cp, 0); if (!local || !skb->dev) { /* drop the old route when skb is not shared */ skb_dst_drop(skb); skb_dst_set(skb, &rt->dst); } else { /* destined to loopback, do we need to change route? */ dst_release(&rt->dst); } /* Another hack: avoid icmp_send in ip_fragment */ skb->local_df = 1; IP_VS_XMIT_NAT(NFPROTO_IPV6, skb, cp, local); rc = NF_STOLEN; goto out; tx_error_icmp: dst_link_failure(skb); tx_error: dev_kfree_skb(skb); rc = NF_STOLEN; out: LeaveFunction(10); return rc; tx_error_put: dst_release(&rt->dst); goto tx_error; }
int ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp, struct ip_vs_iphdr *ipvsh) { struct rt6_info *rt; /* Route to the other host */ struct in6_addr saddr; /* Source for tunnel */ struct net_device *tdev; /* Device to other host */ struct ipv6hdr *old_iph = ipv6_hdr(skb); struct ipv6hdr *iph; /* Our new IP header */ unsigned int max_headroom; /* The extra header space needed */ int ret, local; EnterFunction(10); rcu_read_lock(); local = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, &saddr, ipvsh, 1, IP_VS_RT_MODE_LOCAL | IP_VS_RT_MODE_NON_LOCAL | IP_VS_RT_MODE_TUNNEL); if (local < 0) goto tx_error; if (local) { rcu_read_unlock(); return ip_vs_send_or_cont(NFPROTO_IPV6, skb, cp, 1); } rt = (struct rt6_info *) skb_dst(skb); tdev = rt->dst.dev; /* * Okay, now see if we can stuff it in the buffer as-is. */ max_headroom = LL_RESERVED_SPACE(tdev) + sizeof(struct ipv6hdr); if (skb_headroom(skb) < max_headroom || skb_cloned(skb)) { struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom); if (!new_skb) goto tx_error; consume_skb(skb); skb = new_skb; old_iph = ipv6_hdr(skb); } skb->transport_header = skb->network_header; skb_push(skb, sizeof(struct ipv6hdr)); skb_reset_network_header(skb); memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); /* * Push down and install the IPIP header. */ iph = ipv6_hdr(skb); iph->version = 6; iph->nexthdr = IPPROTO_IPV6; iph->payload_len = old_iph->payload_len; be16_add_cpu(&iph->payload_len, sizeof(*old_iph)); iph->priority = old_iph->priority; memset(&iph->flow_lbl, 0, sizeof(iph->flow_lbl)); iph->daddr = cp->daddr.in6; iph->saddr = saddr; iph->hop_limit = old_iph->hop_limit; /* Another hack: avoid icmp_send in ip_fragment */ skb->local_df = 1; ret = ip_vs_tunnel_xmit_prepare(skb, cp); if (ret == NF_ACCEPT) ip6_local_out(skb); else if (ret == NF_DROP) kfree_skb(skb); rcu_read_unlock(); LeaveFunction(10); return NF_STOLEN; tx_error: kfree_skb(skb); rcu_read_unlock(); LeaveFunction(10); return NF_STOLEN; }
int ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp) { struct rt6_info *rt; /* Route to the other host */ int mtu; EnterFunction(10); if (!(rt = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, NULL, 0, (IP_VS_RT_MODE_LOCAL | IP_VS_RT_MODE_NON_LOCAL)))) goto tx_error_icmp; if (__ip_vs_is_local_route6(rt)) { dst_release(&rt->dst); IP_VS_XMIT(NFPROTO_IPV6, skb, cp, 1); } /* MTU checking */ mtu = dst_mtu(&rt->dst); if (skb->len > mtu) { if (!skb->dev) { struct net *net = dev_net(skb_dst(skb)->dev); skb->dev = net->loopback_dev; } icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); dst_release(&rt->dst); IP_VS_DBG_RL("%s(): frag needed\n", __func__); goto tx_error; } /* * Call ip_send_check because we are not sure it is called * after ip_defrag. Is copy-on-write needed? */ skb = skb_share_check(skb, GFP_ATOMIC); if (unlikely(skb == NULL)) { dst_release(&rt->dst); return NF_STOLEN; } /* drop old route */ skb_dst_drop(skb); skb_dst_set(skb, &rt->dst); /* Another hack: avoid icmp_send in ip_fragment */ skb->local_df = 1; IP_VS_XMIT(NFPROTO_IPV6, skb, cp, 0); LeaveFunction(10); return NF_STOLEN; tx_error_icmp: dst_link_failure(skb); tx_error: kfree_skb(skb); LeaveFunction(10); return NF_STOLEN; }
int ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp, struct ip_vs_iphdr *ipvsh) { struct rt6_info *rt; /* Route to the other host */ int local, rc; EnterFunction(10); rcu_read_lock(); /* check if it is a connection of no-client-port */ if (unlikely(cp->flags & IP_VS_CONN_F_NO_CPORT && !ipvsh->fragoffs)) { __be16 _pt, *p; p = skb_header_pointer(skb, ipvsh->len, sizeof(_pt), &_pt); if (p == NULL) goto tx_error; ip_vs_conn_fill_cport(cp, *p); IP_VS_DBG(10, "filled cport=%d\n", ntohs(*p)); } local = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, NULL, ipvsh, 0, IP_VS_RT_MODE_LOCAL | IP_VS_RT_MODE_NON_LOCAL | IP_VS_RT_MODE_RDR); if (local < 0) goto tx_error; rt = (struct rt6_info *) skb_dst(skb); /* * Avoid duplicate tuple in reply direction for NAT traffic * to local address when connection is sync-ed */ #if IS_ENABLED(CONFIG_NF_CONNTRACK) if (cp->flags & IP_VS_CONN_F_SYNC && local) { enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); if (ct && !nf_ct_is_untracked(ct)) { IP_VS_DBG_RL_PKT(10, AF_INET6, pp, skb, 0, "ip_vs_nat_xmit_v6(): " "stopping DNAT to local address"); goto tx_error; } } #endif /* From world but DNAT to loopback address? */ if (local && skb->dev && !(skb->dev->flags & IFF_LOOPBACK) && ipv6_addr_type(&rt->rt6i_dst.addr) & IPV6_ADDR_LOOPBACK) { IP_VS_DBG_RL_PKT(1, AF_INET6, pp, skb, 0, "ip_vs_nat_xmit_v6(): " "stopping DNAT to loopback address"); goto tx_error; } /* copy-on-write the packet before mangling it */ if (!skb_make_writable(skb, sizeof(struct ipv6hdr))) goto tx_error; if (skb_cow(skb, rt->dst.dev->hard_header_len)) goto tx_error; /* mangle the packet */ if (pp->dnat_handler && !pp->dnat_handler(skb, pp, cp, ipvsh)) goto tx_error; ipv6_hdr(skb)->daddr = cp->daddr.in6; IP_VS_DBG_PKT(10, AF_INET6, pp, skb, 0, "After DNAT"); /* FIXME: when application helper enlarges the packet and the length is larger than the MTU of outgoing device, there will be still MTU problem. */ /* Another hack: avoid icmp_send in ip_fragment */ skb->local_df = 1; rc = ip_vs_nat_send_or_cont(NFPROTO_IPV6, skb, cp, local); rcu_read_unlock(); LeaveFunction(10); return rc; tx_error: LeaveFunction(10); kfree_skb(skb); rcu_read_unlock(); return NF_STOLEN; }
/* * IP Tunneling transmitter * * This function encapsulates the packet in a new IP packet, its * destination will be set to cp->daddr. Most code of this function * is taken from ipip.c. * * It is used in VS/TUN cluster. The load balancer selects a real * server from a cluster based on a scheduling algorithm, * encapsulates the request packet and forwards it to the selected * server. For example, all real servers are configured with * "ifconfig tunl0 <Virtual IP Address> up". When the server receives * the encapsulated packet, it will decapsulate the packet, processe * the request and return the response packets directly to the client * without passing the load balancer. This can greatly increase the * scalability of virtual server. * * Used for ANY protocol */ int ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp, struct ip_vs_iphdr *ipvsh) { struct netns_ipvs *ipvs = net_ipvs(skb_net(skb)); struct rtable *rt; /* Route to the other host */ __be32 saddr; /* Source for tunnel */ struct net_device *tdev; /* Device to other host */ struct iphdr *old_iph = ip_hdr(skb); u8 tos = old_iph->tos; __be16 df; struct iphdr *iph; /* Our new IP header */ unsigned int max_headroom; /* The extra header space needed */ int ret, local; EnterFunction(10); rcu_read_lock(); local = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip, IP_VS_RT_MODE_LOCAL | IP_VS_RT_MODE_NON_LOCAL | IP_VS_RT_MODE_CONNECT | IP_VS_RT_MODE_TUNNEL, &saddr); if (local < 0) goto tx_error; if (local) { rcu_read_unlock(); return ip_vs_send_or_cont(NFPROTO_IPV4, skb, cp, 1); } rt = skb_rtable(skb); tdev = rt->dst.dev; /* Copy DF, reset fragment offset and MF */ df = sysctl_pmtu_disc(ipvs) ? old_iph->frag_off & htons(IP_DF) : 0; /* * Okay, now see if we can stuff it in the buffer as-is. */ max_headroom = LL_RESERVED_SPACE(tdev) + sizeof(struct iphdr); if (skb_headroom(skb) < max_headroom || skb_cloned(skb)) { struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom); if (!new_skb) goto tx_error; consume_skb(skb); skb = new_skb; old_iph = ip_hdr(skb); } skb->transport_header = skb->network_header; /* fix old IP header checksum */ ip_send_check(old_iph); skb_push(skb, sizeof(struct iphdr)); skb_reset_network_header(skb); memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); /* * Push down and install the IPIP header. */ iph = ip_hdr(skb); iph->version = 4; iph->ihl = sizeof(struct iphdr)>>2; iph->frag_off = df; iph->protocol = IPPROTO_IPIP; iph->tos = tos; iph->daddr = cp->daddr.ip; iph->saddr = saddr; iph->ttl = old_iph->ttl; ip_select_ident(skb, NULL); /* Another hack: avoid icmp_send in ip_fragment */ skb->local_df = 1; ret = ip_vs_tunnel_xmit_prepare(skb, cp); if (ret == NF_ACCEPT) ip_local_out(skb); else if (ret == NF_DROP) kfree_skb(skb); rcu_read_unlock(); LeaveFunction(10); return NF_STOLEN; tx_error: kfree_skb(skb); rcu_read_unlock(); LeaveFunction(10); return NF_STOLEN; }
int ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp, int offset, unsigned int hooknum, struct ip_vs_iphdr *ipvsh) { struct rt6_info *rt; /* Route to the other host */ int rc; int local; int rt_mode; EnterFunction(10); /* The ICMP packet for VS/TUN, VS/DR and LOCALNODE will be forwarded directly here, because there is no need to translate address/port back */ if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ) { if (cp->packet_xmit) rc = cp->packet_xmit(skb, cp, pp, ipvsh); else rc = NF_ACCEPT; /* do not touch skb anymore */ atomic_inc(&cp->in_pkts); goto out; } /* * mangle and send the packet here (only for VS/NAT) */ /* LOCALNODE from FORWARD hook is not supported */ rt_mode = (hooknum != NF_INET_FORWARD) ? IP_VS_RT_MODE_LOCAL | IP_VS_RT_MODE_NON_LOCAL | IP_VS_RT_MODE_RDR : IP_VS_RT_MODE_NON_LOCAL; rcu_read_lock(); local = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, NULL, ipvsh, 0, rt_mode); if (local < 0) goto tx_error; rt = (struct rt6_info *) skb_dst(skb); /* * Avoid duplicate tuple in reply direction for NAT traffic * to local address when connection is sync-ed */ #if IS_ENABLED(CONFIG_NF_CONNTRACK) if (cp->flags & IP_VS_CONN_F_SYNC && local) { enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); if (ct && !nf_ct_is_untracked(ct)) { IP_VS_DBG(10, "%s(): " "stopping DNAT to local address %pI6\n", __func__, &cp->daddr.in6); goto tx_error; } } #endif /* From world but DNAT to loopback address? */ if (local && skb->dev && !(skb->dev->flags & IFF_LOOPBACK) && ipv6_addr_type(&rt->rt6i_dst.addr) & IPV6_ADDR_LOOPBACK) { IP_VS_DBG(1, "%s(): " "stopping DNAT to loopback %pI6\n", __func__, &cp->daddr.in6); goto tx_error; } /* copy-on-write the packet before mangling it */ if (!skb_make_writable(skb, offset)) goto tx_error; if (skb_cow(skb, rt->dst.dev->hard_header_len)) goto tx_error; ip_vs_nat_icmp_v6(skb, pp, cp, 0); /* Another hack: avoid icmp_send in ip_fragment */ skb->local_df = 1; rc = ip_vs_nat_send_or_cont(NFPROTO_IPV6, skb, cp, local); rcu_read_unlock(); goto out; tx_error: kfree_skb(skb); rcu_read_unlock(); rc = NF_STOLEN; out: LeaveFunction(10); return rc; }
/* * It is hooked at the NF_IP_FORWARD chain, used only for VS/NAT. * Check if outgoing packet belongs to the established ip_vs_conn, * rewrite addresses of the packet and send it on its way... */ static unsigned int ip_vs_out(unsigned int hooknum, struct sk_buff **pskb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { struct sk_buff *skb = *pskb; struct iphdr *iph; struct ip_vs_protocol *pp; struct ip_vs_conn *cp; int ihl; EnterFunction(11); if (skb->ipvs_property) return NF_ACCEPT; iph = skb->nh.iph; if (unlikely(iph->protocol == IPPROTO_ICMP)) { int related, verdict = ip_vs_out_icmp(pskb, &related); if (related) return verdict; skb = *pskb; iph = skb->nh.iph; } pp = ip_vs_proto_get(iph->protocol); if (unlikely(!pp)) return NF_ACCEPT; /* reassemble IP fragments */ if (unlikely(iph->frag_off & __constant_htons(IP_MF|IP_OFFSET) && !pp->dont_defrag)) { skb = ip_vs_gather_frags(skb, IP_DEFRAG_VS_OUT); if (!skb) return NF_STOLEN; iph = skb->nh.iph; *pskb = skb; } ihl = iph->ihl << 2; /* * Check if the packet belongs to an existing entry */ cp = pp->conn_out_get(skb, pp, iph, ihl, 0); if (unlikely(!cp)) { if (sysctl_ip_vs_nat_icmp_send && (pp->protocol == IPPROTO_TCP || pp->protocol == IPPROTO_UDP)) { __u16 _ports[2], *pptr; pptr = skb_header_pointer(skb, ihl, sizeof(_ports), _ports); if (pptr == NULL) return NF_ACCEPT; /* Not for me */ if (ip_vs_lookup_real_service(iph->protocol, iph->saddr, pptr[0])) { /* * Notify the real server: there is no * existing entry if it is not RST * packet or not TCP packet. */ if (iph->protocol != IPPROTO_TCP || !is_tcp_reset(skb)) { icmp_send(skb,ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); return NF_DROP; } } } IP_VS_DBG_PKT(12, pp, skb, 0, "packet continues traversal as normal"); return NF_ACCEPT; } IP_VS_DBG_PKT(11, pp, skb, 0, "Outgoing packet"); if (!ip_vs_make_skb_writable(pskb, ihl)) goto drop; /* mangle the packet */ if (pp->snat_handler && !pp->snat_handler(pskb, pp, cp)) goto drop; skb = *pskb; skb->nh.iph->saddr = cp->vaddr; ip_send_check(skb->nh.iph); /* For policy routing, packets originating from this * machine itself may be routed differently to packets * passing through. We want this packet to be routed as * if it came from this machine itself. So re-compute * the routing information. */ if (ip_route_me_harder(pskb, RTN_LOCAL) != 0) goto drop; skb = *pskb; IP_VS_DBG_PKT(10, pp, skb, 0, "After SNAT"); ip_vs_out_stats(cp, skb); ip_vs_set_state(cp, IP_VS_DIR_OUTPUT, skb, pp); ip_vs_conn_put(cp); skb->ipvs_property = 1; LeaveFunction(11); return NF_ACCEPT; drop: ip_vs_conn_put(cp); kfree_skb(*pskb); return NF_STOLEN; }
/* Parse a HTTP-header. Be careful for buffer-overflows here, this is the most important place for this, since the remote-user controls the data. */ void ParseHeader(char *Buffer,const int length, struct http_request *Head) { char *Endval,*EOL,*tmp; EnterFunction("ParseHeader"); Endval = Buffer + length; /* We want to parse only the first header if multiple headers are present */ tmp = strstr(Buffer,"\r\n\r\n"); if (tmp!=NULL) Endval = tmp; while (Buffer<Endval) { if (isspace(Buffer[0])) { Buffer++; continue; } EOL=strchr(Buffer,'\n'); if (EOL==NULL) EOL=Endval; if (EOL-Buffer<4) { Buffer++; continue; } if (strncmp("GET ",Buffer,4)==0) { int PrefixLen; Buffer+=4; tmp=strchr(Buffer,' '); if (tmp==0) { tmp=EOL-1; Head->HTTPVER = 9; } else Head->HTTPVER = 10; if (tmp>Endval) continue; strncpy(Head->FileName,sysctl_khttpd_docroot,sizeof(Head->FileName)); PrefixLen = strlen(sysctl_khttpd_docroot); Head->FileNameLength = min(255,tmp-Buffer+PrefixLen); strncat(Head->FileName,Buffer,min(255-PrefixLen,tmp-Buffer)); Buffer=EOL+1; #ifdef BENCHMARK break; #endif continue; } #ifndef BENCHMARK if (strncmp("If-Modified-Since: ",Buffer,19)==0) { Buffer+=19; strncpy(Head->IMS,Buffer,min(127,EOL-Buffer-1)); Buffer=EOL+1; continue; } if (strncmp("User-Agent: ",Buffer,12)==0) { Buffer+=12; strncpy(Head->Agent,Buffer,min(127,EOL-Buffer-1)); Buffer=EOL+1; continue; } if (strncmp("Host: ",Buffer,6)==0) { Buffer+=6; strncpy(Head->Host,Buffer,min(127,EOL-Buffer-1)); Buffer=EOL+1; continue; } #endif Buffer = EOL+1; /* Skip line */ } LeaveFunction("ParseHeader"); }
void PR_ExecuteProgram (func_t fnum) { int i; int s; eval_t *a, *b, *c; eval_t *ptr; dstatement_t *st; dfunction_t *f, *newf; int runaway; edict_t *ed; int exitdepth; int startFrame; int endFrame; float val; int case_type = -1; float switch_float = 0; // shut up compiler if (!fnum || fnum >= progs->numfunctions) { if (PR_GLOBAL_STRUCT(self)) { ED_Print(PROG_TO_EDICT(PR_GLOBAL_STRUCT(self))); } Host_Error("%s: NULL function", __thisfunc__); } f = &pr_functions[fnum]; runaway = 100000; pr_trace = false; exitdepth = pr_depth; s = EnterFunction(f); #ifdef TIMESNAP_ACTIVE ProgsTimer(); // Init #endif while (1) { s++; // Next statement st = &pr_statements[s]; a = (eval_t *)&pr_globals[(unsigned short)st->a]; b = (eval_t *)&pr_globals[(unsigned short)st->b]; c = (eval_t *)&pr_globals[(unsigned short)st->c]; if (!--runaway) { PR_RunError("runaway loop error"); } #ifndef TIMESNAP_ACTIVE pr_xfunction->profile++; #endif pr_xstatement = s; if (pr_trace) { PrintStatement(st); } switch (st->op) { case OP_ADD_F: c->_float = a->_float + b->_float; break; case OP_ADD_V: c->vector[0] = a->vector[0] + b->vector[0]; c->vector[1] = a->vector[1] + b->vector[1]; c->vector[2] = a->vector[2] + b->vector[2]; break; case OP_SUB_F: c->_float = a->_float - b->_float; break; case OP_SUB_V: c->vector[0] = a->vector[0] - b->vector[0]; c->vector[1] = a->vector[1] - b->vector[1]; c->vector[2] = a->vector[2] - b->vector[2]; break; case OP_MUL_F: c->_float = a->_float * b->_float; break; case OP_MUL_V: c->_float = a->vector[0]*b->vector[0] + a->vector[1]*b->vector[1] + a->vector[2]*b->vector[2]; break; case OP_MUL_FV: c->vector[0] = a->_float * b->vector[0]; c->vector[1] = a->_float * b->vector[1]; c->vector[2] = a->_float * b->vector[2]; break; case OP_MUL_VF: c->vector[0] = b->_float * a->vector[0]; c->vector[1] = b->_float * a->vector[1]; c->vector[2] = b->_float * a->vector[2]; break; case OP_DIV_F: c->_float = a->_float / b->_float; break; case OP_BITAND: c->_float = (int)a->_float & (int)b->_float; break; case OP_BITOR: c->_float = (int)a->_float | (int)b->_float; break; case OP_GE: c->_float = a->_float >= b->_float; break; case OP_LE: c->_float = a->_float <= b->_float; break; case OP_GT: c->_float = a->_float > b->_float; break; case OP_LT: c->_float = a->_float < b->_float; break; case OP_AND: c->_float = a->_float && b->_float; break; case OP_OR: c->_float = a->_float || b->_float; break; case OP_NOT_F: c->_float = !a->_float; break; case OP_NOT_V: c->_float = !a->vector[0] && !a->vector[1] && !a->vector[2]; break; case OP_NOT_S: c->_float = !a->string || !*PR_GetString(a->string); break; case OP_NOT_FNC: c->_float = !a->function; break; case OP_NOT_ENT: c->_float = (PROG_TO_EDICT(a->edict) == sv.edicts); break; case OP_EQ_F: c->_float = a->_float == b->_float; break; case OP_EQ_V: c->_float = (a->vector[0] == b->vector[0]) && (a->vector[1] == b->vector[1]) && (a->vector[2] == b->vector[2]); break; case OP_EQ_S: c->_float = !strcmp(PR_GetString(a->string), PR_GetString(b->string)); break; case OP_EQ_E: c->_float = a->_int == b->_int; break; case OP_EQ_FNC: c->_float = a->function == b->function; break; case OP_NE_F: c->_float = a->_float != b->_float; break; case OP_NE_V: c->_float = (a->vector[0] != b->vector[0]) || (a->vector[1] != b->vector[1]) || (a->vector[2] != b->vector[2]); break; case OP_NE_S: c->_float = strcmp(PR_GetString(a->string), PR_GetString(b->string)); break; case OP_NE_E: c->_float = a->_int != b->_int; break; case OP_NE_FNC: c->_float = a->function != b->function; break; case OP_STORE_F: case OP_STORE_ENT: case OP_STORE_FLD: // integers case OP_STORE_S: case OP_STORE_FNC: // pointers b->_int = a->_int; break; case OP_STORE_V: b->vector[0] = a->vector[0]; b->vector[1] = a->vector[1]; b->vector[2] = a->vector[2]; break; case OP_STOREP_F: case OP_STOREP_ENT: case OP_STOREP_FLD: // integers case OP_STOREP_S: case OP_STOREP_FNC: // pointers ptr = (eval_t *)((byte *)sv.edicts + b->_int); ptr->_int = a->_int; break; case OP_STOREP_V: ptr = (eval_t *)((byte *)sv.edicts + b->_int); ptr->vector[0] = a->vector[0]; ptr->vector[1] = a->vector[1]; ptr->vector[2] = a->vector[2]; break; case OP_MULSTORE_F: // f *= f b->_float *= a->_float; break; case OP_MULSTORE_V: // v *= f b->vector[0] *= a->_float; b->vector[1] *= a->_float; b->vector[2] *= a->_float; break; case OP_MULSTOREP_F: // e.f *= f ptr = (eval_t *)((byte *)sv.edicts + b->_int); c->_float = (ptr->_float *= a->_float); break; case OP_MULSTOREP_V: // e.v *= f ptr = (eval_t *)((byte *)sv.edicts + b->_int); c->vector[0] = (ptr->vector[0] *= a->_float); c->vector[0] = (ptr->vector[1] *= a->_float); c->vector[0] = (ptr->vector[2] *= a->_float); break; case OP_DIVSTORE_F: // f /= f b->_float /= a->_float; break; case OP_DIVSTOREP_F: // e.f /= f ptr = (eval_t *)((byte *)sv.edicts + b->_int); c->_float = (ptr->_float /= a->_float); break; case OP_ADDSTORE_F: // f += f b->_float += a->_float; break; case OP_ADDSTORE_V: // v += v b->vector[0] += a->vector[0]; b->vector[1] += a->vector[1]; b->vector[2] += a->vector[2]; break; case OP_ADDSTOREP_F: // e.f += f ptr = (eval_t *)((byte *)sv.edicts + b->_int); c->_float = (ptr->_float += a->_float); break; case OP_ADDSTOREP_V: // e.v += v ptr = (eval_t *)((byte *)sv.edicts + b->_int); c->vector[0] = (ptr->vector[0] += a->vector[0]); c->vector[1] = (ptr->vector[1] += a->vector[1]); c->vector[2] = (ptr->vector[2] += a->vector[2]); break; case OP_SUBSTORE_F: // f -= f b->_float -= a->_float; break; case OP_SUBSTORE_V: // v -= v b->vector[0] -= a->vector[0]; b->vector[1] -= a->vector[1]; b->vector[2] -= a->vector[2]; break; case OP_SUBSTOREP_F: // e.f -= f ptr = (eval_t *)((byte *)sv.edicts + b->_int); c->_float = (ptr->_float -= a->_float); break; case OP_SUBSTOREP_V: // e.v -= v ptr = (eval_t *)((byte *)sv.edicts + b->_int); c->vector[0] = (ptr->vector[0] -= a->vector[0]); c->vector[1] = (ptr->vector[1] -= a->vector[1]); c->vector[2] = (ptr->vector[2] -= a->vector[2]); break; case OP_ADDRESS: ed = PROG_TO_EDICT(a->edict); #ifdef PARANOID NUM_FOR_EDICT(ed); // Make sure it's in range #endif if (ed == (edict_t *)sv.edicts && sv.state == ss_active) { PR_RunError("assignment to world entity"); } c->_int = (byte *)((int *)&ed->v + b->_int)-(byte *)sv.edicts; break; case OP_LOAD_F: case OP_LOAD_FLD: case OP_LOAD_ENT: case OP_LOAD_S: case OP_LOAD_FNC: ed = PROG_TO_EDICT(a->edict); #ifdef PARANOID NUM_FOR_EDICT(ed); // Make sure it's in range #endif a = (eval_t *)((int *)&ed->v + b->_int); c->_int = a->_int; break; case OP_LOAD_V: ed = PROG_TO_EDICT(a->edict); #ifdef PARANOID NUM_FOR_EDICT(ed); // Make sure it's in range #endif a = (eval_t *)((int *)&ed->v + b->_int); c->vector[0] = a->vector[0]; c->vector[1] = a->vector[1]; c->vector[2] = a->vector[2]; break; case OP_FETCH_GBL_F: case OP_FETCH_GBL_S: case OP_FETCH_GBL_E: case OP_FETCH_GBL_FNC: i = (int)b->_float; if (i < 0 || i > G_INT((unsigned short)st->a - 1)) { PR_RunError("array index out of bounds: %d", i); } a = (eval_t *)&pr_globals[(unsigned short)st->a + i]; c->_int = a->_int; break; case OP_FETCH_GBL_V: i = (int)b->_float; if (i < 0 || i > G_INT((unsigned short)st->a - 1)) { PR_RunError("array index out of bounds: %d", i); } a = (eval_t *)&pr_globals[(unsigned short)st->a + ((int)b->_float)*3]; c->vector[0] = a->vector[0]; c->vector[1] = a->vector[1]; c->vector[2] = a->vector[2]; break; case OP_IFNOT: if (!a->_int) { s += st->b - 1; // -1 to offset the s++ } break; case OP_IF: if (a->_int) { s += st->b - 1; // -1 to offset the s++ } break; case OP_GOTO: s += st->a - 1; // -1 to offset the s++ break; case OP_CALL8: case OP_CALL7: case OP_CALL6: case OP_CALL5: case OP_CALL4: case OP_CALL3: case OP_CALL2: // Copy second arg to shared space VectorCopy(c->vector, G_VECTOR(OFS_PARM1)); case OP_CALL1: // Copy first arg to shared space VectorCopy(b->vector, G_VECTOR(OFS_PARM0)); case OP_CALL0: pr_argc = st->op-OP_CALL0; if (!a->function) { PR_RunError("NULL function"); } newf = &pr_functions[a->function]; if (newf->first_statement < 0) { // Built-in function i = -newf->first_statement; if (i >= pr_numbuiltins) { PR_RunError("Bad builtin call number"); } pr_builtins[i](); break; } // Normal function #ifdef TIMESNAP_ACTIVE pr_xfunction->profile += ProgsTimer(); #endif s = EnterFunction(newf); break; case OP_DONE: case OP_RETURN: pr_globals[OFS_RETURN] = pr_globals[(unsigned short)st->a]; pr_globals[OFS_RETURN + 1] = pr_globals[(unsigned short)st->a + 1]; pr_globals[OFS_RETURN + 2] = pr_globals[(unsigned short)st->a + 2]; #ifdef TIMESNAP_ACTIVE pr_xfunction->profile += ProgsTimer(); #endif s = LeaveFunction(); if (pr_depth == exitdepth) { // Done return; } break; case OP_STATE: ed = PROG_TO_EDICT(PR_GLOBAL_STRUCT(self)); /* Id 1.07 changes #ifdef FPS_20 ed->v.nextthink = PR_GLOBAL_STRUCT(time) + 0.05; #else ed->v.nextthink = PR_GLOBAL_STRUCT(time) + 0.1; #endif */ ed->v.nextthink = PR_GLOBAL_STRUCT(time) + HX_FRAME_TIME; if (a->_float != ed->v.frame) { ed->v.frame = a->_float; } ed->v.think = b->function; break; case OP_CSTATE: // Cycle state ed = PROG_TO_EDICT(PR_GLOBAL_STRUCT(self)); ed->v.nextthink = PR_GLOBAL_STRUCT(time) + HX_FRAME_TIME; ed->v.think = pr_xfunction - pr_functions; if (is_progdefs111) pr_global_struct_v111->cycle_wrapped = false; else pr_global_struct->cycle_wrapped = false; startFrame = (int)a->_float; endFrame = (int)b->_float; if (startFrame <= endFrame) { // Increment if (ed->v.frame < startFrame || ed->v.frame > endFrame) { ed->v.frame = startFrame; break; } ed->v.frame++; if (ed->v.frame > endFrame) { if (is_progdefs111) pr_global_struct_v111->cycle_wrapped = true; else pr_global_struct->cycle_wrapped = true; ed->v.frame = startFrame; } break; } // Decrement if (ed->v.frame > startFrame || ed->v.frame < endFrame) { ed->v.frame = startFrame; break; } ed->v.frame--; if (ed->v.frame < endFrame) { if (is_progdefs111) pr_global_struct_v111->cycle_wrapped = true; else pr_global_struct->cycle_wrapped = true; ed->v.frame = startFrame; } break; case OP_CWSTATE: // Cycle weapon state ed = PROG_TO_EDICT(PR_GLOBAL_STRUCT(self)); ed->v.nextthink = PR_GLOBAL_STRUCT(time) + HX_FRAME_TIME; ed->v.think = pr_xfunction - pr_functions; if (is_progdefs111) pr_global_struct_v111->cycle_wrapped = false; else pr_global_struct->cycle_wrapped = false; startFrame = (int)a->_float; endFrame = (int)b->_float; if (startFrame <= endFrame) { // Increment if (ed->v.weaponframe < startFrame || ed->v.weaponframe > endFrame) { ed->v.weaponframe = startFrame; break; } ed->v.weaponframe++; if (ed->v.weaponframe > endFrame) { if (is_progdefs111) pr_global_struct_v111->cycle_wrapped = true; else pr_global_struct->cycle_wrapped = true; ed->v.weaponframe = startFrame; } break; } // Decrement if (ed->v.weaponframe > startFrame || ed->v.weaponframe < endFrame) { ed->v.weaponframe = startFrame; break; } ed->v.weaponframe--; if (ed->v.weaponframe < endFrame) { if (is_progdefs111) pr_global_struct_v111->cycle_wrapped = true; else pr_global_struct->cycle_wrapped = true; ed->v.weaponframe = startFrame; } break; case OP_THINKTIME: ed = PROG_TO_EDICT(a->edict); #ifdef PARANOID NUM_FOR_EDICT(ed); // Make sure it's in range #endif if (ed == (edict_t *)sv.edicts && sv.state == ss_active) { PR_RunError("assignment to world entity"); } ed->v.nextthink = PR_GLOBAL_STRUCT(time) + b->_float; break; case OP_BITSET: // f (+) f b->_float = (int)b->_float | (int)a->_float; break; case OP_BITSETP: // e.f (+) f ptr = (eval_t *)((byte *)sv.edicts + b->_int); ptr->_float = (int)ptr->_float | (int)a->_float; break; case OP_BITCLR: // f (-) f b->_float = (int)b->_float & ~((int)a->_float); break; case OP_BITCLRP: // e.f (-) f ptr = (eval_t *)((byte *)sv.edicts + b->_int); ptr->_float = (int)ptr->_float & ~((int)a->_float); break; case OP_RAND0: // val = (rand() & 0x7fff) / ((float)0x7fff); val = rand() * (1.0 / RAND_MAX); G_FLOAT(OFS_RETURN) = val; break; case OP_RAND1: val = rand() * (1.0 / RAND_MAX) * a->_float; G_FLOAT(OFS_RETURN) = val; break; case OP_RAND2: if (a->_float < b->_float) { val = a->_float + (rand() * (1.0 / RAND_MAX) * (b->_float - a->_float)); } else { val = b->_float + (rand() * (1.0 / RAND_MAX) * (a->_float - b->_float)); } G_FLOAT(OFS_RETURN) = val; break; case OP_RANDV0: val = rand() * (1.0 / RAND_MAX); G_FLOAT(OFS_RETURN + 0) = val; val = rand() * (1.0 / RAND_MAX); G_FLOAT(OFS_RETURN + 1) = val; val = rand() * (1.0 / RAND_MAX); G_FLOAT(OFS_RETURN + 2) = val; break; case OP_RANDV1: val = rand() * (1.0 / RAND_MAX) * a->vector[0]; G_FLOAT(OFS_RETURN + 0) = val; val = rand() * (1.0 / RAND_MAX) * a->vector[1]; G_FLOAT(OFS_RETURN + 1) = val; val = rand() * (1.0 / RAND_MAX) * a->vector[2]; G_FLOAT(OFS_RETURN + 2) = val; break; case OP_RANDV2: for (i = 0; i < 3; i++) { if (a->vector[i] < b->vector[i]) { val = a->vector[i] + (rand() * (1.0 / RAND_MAX) * (b->vector[i] - a->vector[i])); } else { val = b->vector[i] + (rand() * (1.0 / RAND_MAX) * (a->vector[i] - b->vector[i])); } G_FLOAT(OFS_RETURN + i) = val; } break; case OP_SWITCH_F: case_type = SWITCH_F; switch_float = a->_float; s += st->b - 1; // -1 to offset the s++ break; case OP_SWITCH_V: PR_RunError("switch v not done yet!"); break; case OP_SWITCH_S: PR_RunError("switch s not done yet!"); break; case OP_SWITCH_E: PR_RunError("switch e not done yet!"); break; case OP_SWITCH_FNC: PR_RunError("switch fnc not done yet!"); break; case OP_CASERANGE: if (case_type != SWITCH_F) PR_RunError("caserange f****d!"); if ((switch_float >= a->_float) && (switch_float <= b->_float)) { s += st->c - 1; // -1 to offset the s++ } break; case OP_CASE: switch (case_type) { case SWITCH_F: if (switch_float == a->_float) { s += st->b - 1; // -1 to offset the s++ } break; case SWITCH_V: case SWITCH_S: case SWITCH_E: case SWITCH_FNC: PR_RunError("case not done yet!"); break; default: PR_RunError("f****d case!"); } break; default: PR_RunError("Bad opcode %i", st->op); } } // end of while(1) loop }
/* The function "OpenFileForSecurity" returns either the "struct file" pointer of the file, or NULL. NULL means "let userspace handle it". */ struct file *OpenFileForSecurity(char *Filename) { struct file *filp; struct DynamicString *List; umode_t permission; EnterFunction("OpenFileForSecurity"); if (Filename==NULL) return NULL; if (strlen(Filename)>=256 ) return NULL; /* Sanity check */ /* Rule no. 1 -- No "?" characters */ #ifndef BENCHMARK if (strchr(Filename,'?')!=NULL) return NULL; /* Intermediate step: decode all %hex sequences */ DecodeHexChars(Filename); /* Rule no. 2 -- Must start with a "/" */ if (Filename[0]!='/') return NULL; #endif /* Rule no. 3 -- Does the file exist ? */ filp = filp_open(Filename, O_RDONLY, 0); if (IS_ERR(filp)) return NULL; #ifndef BENCHMARK permission = filp->f_dentry->d_inode->i_mode; /* Rule no. 4 : must have enough permissions */ if ((permission & sysctl_khttpd_permreq)==0) { if (filp!=NULL) fput(filp); filp=NULL; return NULL; } /* Rule no. 5 : cannot have "forbidden" permission */ if ((permission & sysctl_khttpd_permforbid)!=0) { if (filp!=NULL) fput(filp); filp=NULL; return NULL; } /* Rule no. 6 : No string in DynamicList can be a substring of the filename */ List = DynamicList; while (List!=NULL) { if (strstr(Filename,List->value)!=NULL) { if (filp!=NULL) fput(filp); filp=NULL; return NULL; } List = List->Next; } #endif LeaveFunction("OpenFileForSecurity - success"); return filp; }